NSJSONSerialization.JSONObjectWithData leaks memory - json

I have a function which uses NSJSONSerialization.JSONObjectWithData, but some memory was not released.
So I tracked down where the leak occurred and tested it with the following function:
private func test() {
for var i = 0; i < 100000; i++ {
let toParse = NSString(string: "{ \"Test\" : [ \"Super mega long JSON-string which is super long because it should be super long because it is easier to see the differences in memory usage with a super long JSON-string than with a short one.\" ] }").dataUsingEncoding(NSUTF8StringEncoding)!
let json = try! NSJSONSerialization.JSONObjectWithData(toParse, options: NSJSONReadingOptions(rawValue: 0))
}
}
The memory-usage of my app before I called test() was 11 MB, the memory-usage after was 74.4 MB (even if I did some other things in my app to give the system some time to release the memory)...
Why is json not released?
Mundi pointed me to autoreleasepool which I hadn't tried yet (insert facepalm here)... so I changed the code to:
autoreleasepool {
self.test()
}
This didn't make any difference, and because Xcode suggested it, I also tried:
autoreleasepool({ () -> () in
self.test()
})
But this also didn't work...
P.S.: Maybe I should add that I'm using Swift 2.0 in Xcode 7 GM.
P.P.S: The test()-function is called from within a
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), {
//... my code ...
self.test()
})
but this shouldn't make any difference...

You are misunderstanding how an autorelease pool works. An autorelease pools keeps hold of allocated memory until the pool is released. Calling a loop 100,000 times inside an autorelease pool means the pool has no chance to release anything, so the memory builds up. Eventually it goes away, when the code has finished running and the autorelease pool is released, but meanwhile your memory usage goes up.
Correct way:
private func test() {
for var i = 0; i < 100000; i++ {
autoreleasepool {
stuff
}
}
}

As you point out in your question, the app arbitrarily releases the memory, so the fact that it is still not release does not mean it would cause a tight memory condition.
You can try enclosing your test routine in an autoreleasepool, similar to Objective-C.
func test() {
autoreleasepool {
// do the test
}
}

Related

Autodesk Viewer memory leak

I have some big memory issues in an angular/typescript app using the forge viewer (v6.6.1). This has also been discussed before: Severe memory leaks in the Autodesk Forge viewer on devices
Whenever we close the component or route to an other page we destroy the current created viewer. For this I use the function viewer.finish(); However it seems that it doesn't release any GPU memory. This is most notable when using models that contain textures. The problem is that after a few times opening this in our app it will crash as to much gpu memory is used.
To see the memory usage buildup I used chrome://tracing/ (using the record category memory-infra).
Here are some screenshots where you can see the memory buildup.
Initial initialisation of the page
after returning to this page after closing it
after returning to this page after closing it a third time
As you can see the memory under textures builds up quite fast. And this is just a light model that we use. With some models is build up in steps of over 250MB.
Here is the part of component code that does the work. I also provided a link to a minimal angular project on github that you can run. When you start the app you can use the toggle button to create / destroy the component and trigger the issue.
public viewer;
public options;
public url = 'MODEL-YOUR-URL-HERE';
#ViewChild('viewer')
public viewerContainer: any;
constructor() { }
ngOnInit() {
this.options = {
env: 'Local',
useADP: false,
language: 'en',
};
Autodesk.Viewing.Initializer(this.options, () => {
this.onEnvInitialized();
});
}
public onEnvInitialized() {
this.viewer = new Autodesk.Viewing.Private.GuiViewer3D(this.viewerContainer.nativeElement, {});
this.viewer.initialize();
this.viewer.loadModel( decodeURI(this.url), {}, () => { }, (aErrorCode) => { } );
}
ngOnDestroy() {
this.viewer.finish();
this.viewer = null;
}
https://github.com/zedero/forge-angular-memory-issue
Engineering's final recommendations are to wait for Viewer v7.0 which is set to release for general access in a few weeks time with multiple bug fixes & improvements on memory management.
In the meantime see if you have any event listeners/custom extensions that might be holding on to references to nodes etc - remove/unload these and see if that helps.

web audio API crashing chrome

I'm trying to build something using the processor node here. Almost anything I do in terms of debugging it crashes chrome. Specifically the tab. Whenever I bring up dev tools, and 100% of the time i put a breakpoint in the onaudioprocess node, the tab dies and I have to either find the chrome helper process for that tab or force quit chrome altogether to get started agin. Its basically crippled my development for the time being. Is this a known issue? Do I need to take certain precautions to prevent chrome from crashing? Are the real time aspects are the web audio api simply not debuggable?
Without seeing your code, it's a bit hard to diagnose the problem.
Does running this code snippet crash your browser tab?
let audioCtx = new (window.AudioContext || window.webkitAudioContext)();
function onPlay() {
let scriptProcessor = audioCtx.createScriptProcessor(4096, 2, 2);
scriptProcessor.onaudioprocess = onAudioProcess;
scriptProcessor.connect(audioCtx.destination);
let oscillator = audioCtx.createOscillator();
oscillator.type = "sawtooth";
oscillator.frequency.value = 220;
oscillator.connect(scriptProcessor);
oscillator.start();
}
function onAudioProcess(event) {
let { inputBuffer, outputBuffer } = event;
for (let channel = 0; channel < outputBuffer.numberOfChannels; channel++) {
let inputData = inputBuffer.getChannelData(channel);
let outputData = outputBuffer.getChannelData(channel);
for (let sample = 0; sample < inputBuffer.length; sample++) {
outputData[sample] = inputData[sample];
// Add white noise to oscillator.
outputData[sample] += ((Math.random() * 2) - 1) * 0.2;
// Un-comment the following line to crash the browser tab.
// console.log(sample);
}
}
}
<button type="button" onclick="onPlay()">Play</button>
If it crashes, there's something else in your local dev environment causing you problems, because it runs perfectly for me.
If not, then maybe you are doing a console.log() (or some other heavy operation) in your onaudioprocess event handler? Remember, this event handler processes thousands of audio samples every time it is called, so you need to be careful what you do with it. For example, try un-commenting the console.log() line in the code snippet above – your browser tab will crash.

Memory increase every 15 seconds suspected JSON / String issues.

The app I am making is almost complete, however I am seeing a memory increase every 15 seconds until the app crashes. It increases ~10mb/15seconds.
The app is pretty simple.
I call a repeating timer in applicationDidFinishLaunching as shown here:
timer = NSTimer.scheduledTimerWithTimeInterval(5, target: self, selector: "refreshIpAddresses", userInfo: nil, repeats: true)
the timer calls a function called refreshIpAddresses() which calls 3 more functions. This is show below:
func refreshIpAddresses() {
getPrivateIp()
getIpData()
getDnsData()
}
Each of these are similar, so I will just demo one of them. The code below is the method getDnsData().
func getDnsData() {
Alamofire.request(.GET, dataSourceURL2!)
.responseJSON { response in
if (response.result.value != nil) {
let json2 = JSON(response.result.value!)
let json3 = json2["dns"]
let geo = json3["geo"].stringValue
let ip = json3["ip"].stringValue
self.dnsIp.title = "DNS IP: " + ip
self.dnsName.title = "DNS Name: " + geo
} else {
self.dnsIp.title = "No Internet Connection"
self.dnsName.title = "No Internet Connection"
}
}
}
If I comment out the timers, the memory increase stops being an issue.
Is my timer somehow storing information every loop? Should it be invalidated somewhere? Is it my getDnsData() method?
Please help.
EDIT It might not be due to the NSTimer. Can someone guide me how to figure out what the issue is?
Here is the memory leak checks in instruments:

windows 8 app FileOpenPicker np file info

I'm trying to get some file information about a file the user select with the FileOpenPicker, but all the information like the path and name are empty. When I try to view the object in a breakpoint I got the following message:
file = 0x03489cd4 <Information not available, no symbols loaded for shell32.dll>
I use the following code for calling the FileOpenPicker and handeling the file
#include "pch.h"
#include "LocalFilePicker.h"
using namespace concurrency;
using namespace Platform;
using namespace Windows::Storage;
using namespace Windows::Storage::Pickers;
const int LocalFilePicker::AUDIO = 0;
const int LocalFilePicker::VIDEO = 1;
const int LocalFilePicker::IMAGES = 2;
LocalFilePicker::LocalFilePicker()
{
_init();
}
void LocalFilePicker::_init()
{
_openPicker = ref new FileOpenPicker();
_openPicker->ViewMode = PickerViewMode::Thumbnail;
}
void LocalFilePicker::askFile(int categorie)
{
switch (categorie)
{
case 0:
break;
case 1:
_openPicker->SuggestedStartLocation = PickerLocationId::VideosLibrary;
_openPicker->FileTypeFilter->Append(".mp4");
break;
case 2:
break;
default:
break;
}
create_task(_openPicker->PickSingleFileAsync()).then([this](StorageFile^ file)
{
if (file)
{
int n = 0;
wchar_t buf[1024];
_snwprintf_s(buf, 1024, _TRUNCATE, L"Test: '%s'\n", file->Path);
OutputDebugString(buf);
}
else
{
OutputDebugString(L"canceled");
}
});
}
Can anybody see whats wrong with the code or some problems with settings for the app why it isn't work as expected.
First an explanation why you are having trouble debugging, this is going to happen a lot more when you write WinRT programs. First, do make sure that you have the correct debugging engine enabled. Tools + Options, Debugging, General. Ensure that the "Use Managed Compatibility Mode" is turned off.
You can now inspect the "file" option, it should resemble this:
Hard to interpret of course. What you are looking at is a proxy. It is a COM term, a wrapper for COM objects that are not thread-safe or live in another process or machine. The proxy implementation lives in shell32.dll, thus the confuzzling diagnostic message. You can't see the actual object at all, accessing its properties requires calling proxy methods. Something that the debugger is not capable of doing, a proxy marshals the call from one thread to another, that other thread is frozen while the debugger break is active.
That makes you pretty blind, in tough cases you may want to write a littler helper code to store the property in a local variable. Like:
auto path = file->Path;
No trouble inspecting or watching that one. You should now have confidence that there's nothing wrong with file and you get a perfectly good path. Note how writing const wchar_t* path = file->Path; gets you a loud complaint from the compiler.
Which helps you find the bug, you can't pass a Platform::String to a printf() style function. Just like you can't with, say, std::wstring. You need to use an accessor function to convert it. Fix:
_snwprintf_s(buf, 1024, _TRUNCATE,
L"Test: '%s'\n",
file->Path->Data());

How to solve that AttachAsync of a DownloadOperation does not return immediately?

When using the Background Transfer API we must iterate through current data transfers to start them again ahen the App restarts after a termination (i.e. system shutdown). To get progress information and to be able to cancel the data transfers they must be attached using AttachAsync.
My problem is that AttachAsync only returns when the data transfer is finished. That makes sense in some scenarios. But when having multiple data transfers the next transfer in the list would not be started until the currently attached is finished. My solution to this problem was to handle the Task that AttachAsync().AsTask() returns in the classic way (not use await but continuations):
IReadOnlyList<DownloadOperation> currentDownloads =
await BackgroundDownloader.GetCurrentDownloadsAsync();
foreach (var downloadOperation in currentDownloads)
{
Task task = downloadOperation.AttachAsync().AsTask();
DownloadOperation operation = downloadOperation;
task.ContinueWith(_ =>
{
// Handle success
...
}, CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.FromCurrentSynchronizationContext());
task.ContinueWith(_ =>
{
// Handle cancellation
...
}, CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled,
TaskScheduler.FromCurrentSynchronizationContext());
task.ContinueWith(t =>
{
// Handle errors
...
}, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted,
TaskScheduler.FromCurrentSynchronizationContext());
}
It kind of works (in the actual code I add the downloads to a ListBox). The loop iterates through all downloads and executes StartAsync. But the downloads are not really started all at the same time. Only one is runninng at a time and only if it finishes the next one continues.
Any solution for this problem?
The whole point of Task is to allow you to have the option of parallel operations. If you await then you are telling the code to serialize the operations; if you don't await, then you are telling the code to parallelize.
What you can do is add each download task to a list, telling the code to parallelize. You can then wait for tasks to finish, one by one.
How about something like:
IReadOnlyList<DownloadOperation> currentDownloads =
await BackgroundDownloader.GetCurrentDownloadsAsync();
if (currentDownloads.Count > 0)
{
List<Task<DownloadOperation>> tasks = new List<Task<DownloadOperation>>();
foreach (DownloadOperation downloadOperation in currentDownloads)
{
// Attach progress and completion handlers without waiting for completion
tasks.Add(downloadOperation.AttachAsync().AsTask());
}
while (tasks.Count > 0)
{
// wait for ANY download task to finish
Task<DownloadOperation> task = await Task.WhenAny<DownloadOperation>(tasks);
tasks.Remove(task);
// process the completed task...
if (task.IsCanceled)
{
// handle cancel
}
else if (task.IsFaulted)
{
// handle exception
}
else if (task.IsCompleted)
{
DownloadOperation dl = task.Result;
// handle completion (e.g. add to your listbox)
}
else
{
// should never get here....
}
}
}
I hope this is not too late but I know exactly what you are talking about. I'm also trying to resume all downloads when the application starts.
After hours of trying, here's the solution that works.
The trick is to let the download operation resume first before attacking the progress handler.
downloadOperation.Resume();
await downloadOperation.AttachAsync().AsTask(cts.Token);