Macos Catalina
xcode 11.3
Recently, I encountered a strange memory leakage problem when using MLModel. I put the pseudocode as following.
// prediction class
class Prediction {
public:
Prediction(const std::string &mlmodelc_file);
~Prediction();
void RunPrediction();
private:
MLPredictionOptions *options_;
MLModelConfiguration *config_;
MLModel *mlmodel_;
}
Prediction::Prediction() {
// set configuration
options_ = [[MLPredictionOptions alloc] init];
config_ = [[MLModelConfiguration alloc] init];
options_.usesCPUOnly = false;
config_.computeUnits = MLComputeUnitsAll;
// load mlmodelc file
NSError *error = nil;
NSString *model_path_nsstring = [NSString stringWithUTF8String:mlmodelc_file.c_str()];
NSURL *compiled_model_url = [NSURL fileURLWithPath:model_path_nsstring isDirectory:YES];
mlmodel_ = [MLModel modelWithContentsOfURL:compiled_model_url configuration:config_ error:&error];
}
Prediction::~Prediction() {
}
void Prediction::RunPrediction() {
NSError *error = nil;
#autoreleasepool {
[mlmodel_ predictionFromFeatures:model_input options:options_ error:&error];
}
}
// There is no memory leakage, if I just create the prediction once, and run the prediction for a loop.
int main(int argc, char **argv) {
std::shared_ptr<Prediction> pred = std::make_shared<Prediction>(mlmodelc_file);
for (int i = 0; i < 1000; ++i) {
pred->RunPrediction();
}
return 0;
}
// But if I put the creation in the loop, memory leakage occurs.
int main(int argc, char **argv) {
for (int i = 0; i < 1000; ++i) {
std::shared_ptr<Prediction> pred = std::make_shared<Prediction>(mlmodelc_file);
pred->RunPrediction();
}
return 0;
}
The MLPredictionOptions, MLModelConfiguration and MLModel are all ARC objects. They should be auto-released after every loop. But it seems that they are not auto-released. I have enable the ARC in xcode. But the memory still increases from 200MB to 2GB and more.
Related
I am trying to stream AAC encoded audio data received as CMSampleBuffer. AudioConverterFillComplexBuffer returns 0 status code.
But after passing this data to my FFMPEG HLSWriter audio is not correctly saved (short truncated signals).
Below is the sample code.
static OSStatus inInputDataProc(AudioConverterRef inAudioConverter,
UInt32 *ioNumberDataPackets,
AudioBufferList *ioData,
AudioStreamPacketDescription **outDataPacketDescription,
void *inUserData)
{
KFAACEncoder *encoder = (__bridge KFAACEncoder *)(inUserData);
UInt32 requestedPackets = *ioNumberDataPackets;
if(requestedPackets > encoder.cycledBuffer.size / 2)
{
//NSLog(#"PCM buffer isn't full enough!");
*ioNumberDataPackets = 0;
return -1;
}
static size_t staticBuffSize = 4096;
static void* staticBuff = nil;
if(!staticBuff)
{
staticBuff = malloc(staticBuffSize);
}
size_t outputBytesSize = requestedPackets * 2;
[encoder.cycledBuffer popToBuffer:staticBuff bytes: outputBytesSize];
ioData->mBuffers[0].mData = staticBuff;
ioData->mBuffers[0].mDataByteSize = (int)outputBytesSize;
*ioNumberDataPackets = ioData->mBuffers[0].mDataByteSize / 2;
return noErr;
}
- (void) encodeSampleBuffer:(CMSampleBufferRef)sampleBuffer
{
CFRetain(sampleBuffer);
dispatch_async(self.encoderQueue,
^{
if (!_audioConverter)
{
[self setupAACEncoderFromSampleBuffer:sampleBuffer];
}
CMBlockBufferRef blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer);
CMTime pts = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
CFRetain(blockBuffer);
size_t pcmBufferSize = 0;
void* pcmBuffer = nil;
OSStatus status = CMBlockBufferGetDataPointer(blockBuffer, 0, NULL, &pcmBufferSize, &pcmBuffer);
[_cycledBuffer push:pcmBuffer size:pcmBufferSize];
NSError *error = nil;
if (status != kCMBlockBufferNoErr)
{
error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
}
memset(_aacBuffer, 0, _aacBufferSize);
AudioBufferList outAudioBufferList = {0};
outAudioBufferList.mNumberBuffers = 1;
outAudioBufferList.mBuffers[0].mNumberChannels = 1;
outAudioBufferList.mBuffers[0].mDataByteSize = _aacBufferSize;
outAudioBufferList.mBuffers[0].mData = _aacBuffer;
AudioStreamPacketDescription *outPacketDescription = NULL;
UInt32 ioOutputDataPacketSize = 1;
status = AudioConverterFillComplexBuffer(_audioConverter,
inInputDataProc,
(__bridge void *)(self),
&ioOutputDataPacketSize,
&outAudioBufferList,
NULL);
NSData *data = nil;
if (status == 0)
{
NSData *rawAAC = [NSData dataWithBytes:outAudioBufferList.mBuffers[0].mData length:outAudioBufferList.mBuffers[0].mDataByteSize];
if (_addADTSHeader) {
NSData *adtsHeader = [self adtsDataForPacketLength:rawAAC.length];
NSMutableData *fullData = [NSMutableData dataWithData:adtsHeader];
[fullData appendData:rawAAC];
data = fullData;
} else {
data = rawAAC;
}
} else {
error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
}
if (self.delegate) {
KFFrame *frame = [[KFFrame alloc] initWithData:data pts:pts];
NSLog(#"Bytes of data %lu", (unsigned long)data.length);
dispatch_async(self.callbackQueue, ^{
[self.delegate encoder:self encodedFrame:frame];
});
}
CFRelease(sampleBuffer);
CFRelease(blockBuffer);
});
}
I have just recently found Objective Zip Ihave been reading through the instructions to get it set up in my project. However I am not really sure how to use it to decompress some NSData I have that I am wanting to decompress.
I have looked at the example solution and it seems to be performing the unzip on a zip file the code looks roughly like this
ZipFile *unzipFile= [[ZipFile alloc] initWithFileName:filePath mode:ZipFileModeUnzip];
[unzipFile goToFirstFileInZip];
ZipReadStream *read1= [unzipFile readCurrentFileInZip];
give or take some other instructions this is how they show you to use it, their sample code is here
I would like to know how to do the same thing but using NSData? or would I have to convert the NSData into a zipFile? if so how is that performed properly?
The NSData I am trying to unzip if zlib compressed... any example code would be helpful
here it is https://stackoverflow.com/a/6466832/751885
I use the following two methods process NSData
and call
saveToFile
method write on disk.
[[self compressData:uncompressedData] writeToFile:#"fileName.zip" atomically:YES];
Compress:
-(NSData*) compressData:(NSData* )uncompressedData {
if ([uncompressedData length] == 0) return uncompressedData;
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.total_out = 0;
strm.next_in=(Bytef *)[uncompressedData bytes];
strm.avail_in = (unsigned int)[uncompressedData length];
// Compresssion Levels:
// Z_NO_COMPRESSION
// Z_BEST_SPEED
// Z_BEST_COMPRESSION
// Z_DEFAULT_COMPRESSION
if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY) != Z_OK) return nil;
NSMutableData *compressed = [NSMutableData dataWithLength:16384]; // 16K chunks for expansion
do {
if (strm.total_out >= [compressed length])
[compressed increaseLengthBy: 16384];
strm.next_out = [compressed mutableBytes] + strm.total_out;
strm.avail_out = (unsigned int)([compressed length] - strm.total_out);
deflate(&strm, Z_FINISH);
} while (strm.avail_out == 0);
deflateEnd(&strm);
[compressed setLength: strm.total_out];
return [NSData dataWithData:compressed];
}
Uncompress:
-(NSData*) uncompressGZip:(NSData*) compressedData {
if ([compressedData length] == 0) return compressedData;
NSUInteger full_length = [compressedData length];
NSUInteger half_length = [compressedData length] / 2;
NSMutableData *decompressed = [NSMutableData dataWithLength: full_length + half_length];
BOOL done = NO;
int status;
z_stream strm;
strm.next_in = (Bytef *)[compressedData bytes];
strm.avail_in = (unsigned int)[compressedData length];
strm.total_out = 0;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
if (inflateInit2(&strm, (15+32)) != Z_OK) return nil;
while (!done) {
// Make sure we have enough room and reset the lengths.
if (strm.total_out >= [decompressed length]) {
[decompressed increaseLengthBy: half_length];
}
strm.next_out = [decompressed mutableBytes] + strm.total_out;
strm.avail_out = (unsigned int)([decompressed length] - strm.total_out);
// Inflate another chunk.
status = inflate (&strm, Z_SYNC_FLUSH);
if (status == Z_STREAM_END) {
done = YES;
} else if (status != Z_OK) {
break;
}
}
if (inflateEnd (&strm) != Z_OK) return nil;
// Set real length.
if (done) {
[decompressed setLength: strm.total_out];
return [NSData dataWithData: decompressed];
} else {
return nil;
}
}
Am getting errors in this piece of code; I have placed the error messages in the comments. Can't figure it out.
Thanks in advance.
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
#autoreleasepool {
NSMutableString *str = [[NSMutableString alloc]init];
for (int i = 0; i < 10; i++) {
[str appendString:#"Aaron is cool!\n"];
}
// Declare a pointer to an NSError object, but don't instantiate it.
// The NSError instance will only be created if there is, in fact, an error.
NSError *error = nil;
// Pass the error pointer by reference to the NSString method
BOOL success =[str writeToFile:#"/tmp/cool.txt"; // Expected "]"
atomically:YES // Bad receiver type 'int'
encoding:NSUTF8StringEncoding
error:&error];
// Test the returned BOOL, and query the NSError if the write failed
if (success) {
NSLog(#"done writing /tmp/cool.txt");
} else {
NSLog(#"writing /tmp/cool/txt failed:#", error localizedDescription); // Expected ')'
}
}
return 0;
}
If your code doesn't have any typos this is the problem
// Pass the error pointer by reference to the NSString method
BOOL success =[str writeToFile:#"/tmp/cool.txt"; // Expected "]"
atomically:YES // Bad receiver type 'int'
encoding:NSUTF8StringEncoding
error:&error];
Remove the semicolon ";" from here.
BOOL success =[str writeToFile:#"/tmp/cool.txt"; // Expected "]"
try this:
#autoreleasepool {
NSMutableString *str = [[[NSMutableString alloc]init] autorelease];
for (int i = 0; i < 10; i++) {
[str appendString:#"Aaron is cool!\n"];
}
NSError *error = nil;
BOOL success =[str writeToFile:#"/tmp/cool.txt"
atomically:YES
encoding:NSUTF8StringEncoding
error:&error];
if (success) {
NSLog(#"done writing /tmp/cool.txt");
} else {
NSLog(#"writing /tmp/cool/txt failed: %#", [error localizedDescription]);
}
}
return 0;
I'm successfully sending int and CGPoint data in the struct of the GKTank example, BUT I tried desperately to send a NSString. I also tried it with char instead of NSString with no success...
Here's the code for
sending:
NSString *playerName = #"My Name";
NSData *dat = [playerName dataUsingEncoding:NSUTF8StringEncoding];
[BTINconnector sendNetworkPacketwithPacketID:NETWORK_PLAYERNAME withData:dat ofLength:sizeof(dat) reliable:YES];
the method (known from GKTank, modified)
- (void)sendNetworkPacketwithPacketID:(int)packetID withData:(void *)data ofLength:(int)length reliable:(BOOL)howtosend {
//NSLog(#"bmpc:ok 3 send packet to %i",gamePeerId);
// the packet we'll send is resued
static unsigned char networkPacket[kMaxPacketSize];
const unsigned int packetHeaderSize = 2 * sizeof(int); // we have two "ints" for our header
if(length < (kMaxPacketSize - packetHeaderSize)) { // our networkPacket buffer size minus the size of the header info
int *pIntData = (int *)&networkPacket[0];
// header info
pIntData[0] = gamePacketNumber++;
pIntData[1] = packetID;
// copy data in after the header
memcpy( &networkPacket[packetHeaderSize], data, length );
NSData *packet = [NSData dataWithBytes: networkPacket length: (length+8)];
if(howtosend == YES) {
[mySession sendData:packet toPeers:[NSArray arrayWithObject:gamePeerId] withDataMode:GKSendDataReliable error:nil];
} else {
[mySession sendData:packet toPeers:[NSArrayarrayWithObject:gamePeerId] withDataMode:GKSendDataUnreliable error:nil];
}
}
}
and the method for receiving (from GKTank modified by me)
- (void)receiveDataDG:(NSData *)data fromPeer:(NSString *)peer inSession:(GKSession *)session context:(void *)context {
static int lastPacketTime = -1;
unsigned char *incomingPacket = (unsigned char *)[data bytes];
int *pIntData = (int *)&incomingPacket[0];
NSData* nData = (NSData*)&incomingPacket[0];
//NSData* bData = nData[8];
//
// developer check the network time and make sure packers are in order
//
int packetTime = pIntData[0];
int packetID = pIntData[1];
if(packetTime < lastPacketTime && packetID != NETWORK_COINTOSS) {
NSLog(#"bmc: EXITED");
return;
}
lastPacketTime = packetTime;
switch( packetID ) {
case NETWORK_PLAYERNAME:
{
NSData *hjk = [NSData dataWithBytes:&pIntData[2] length:sizeof(int)];
NSString *gotitb = [[NSString alloc] initWithData:hjk encoding:NSUTF8StringEncoding];
NSLog(#"bmc:str %#,%#",gotitb,gotitb);
…
The gotitb returns null, but I don't know why. Please help.
You don't want sizeof(dat) you want [dat length].
I'm getting data from a mysql database using the C api. I can log the data so I know the query is working fine but I need to take it and put it into a dictionary and The Google is not being helpful with that. Can anyone give me a pointer, snippet or link to get me going in the right direction?
- (IBAction)dbConnect:(id)sender {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
MYSQL mysql;
mysql_init(&mysql);
if (!mysql_real_connect(&mysql, "10.1.1.99", "*******", "********", "oldphotoarchive", 0, NULL, 0)) {
NSLog(#"%#", [NSString stringWithUTF8String:mysql_error(&mysql)]);
} else {
MYSQL_RES *result;
MYSQL_ROW row;
unsigned int num_fields;
unsigned int num_rows;
unsigned long *lengths;
if (mysql_query(&mysql,"SELECT * FROM photorecord")) {
// error
} else { // query succeeded, process any data returned by it
result = mysql_store_result(&mysql);
if (result) {
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result))) {
lengths = mysql_fetch_lengths(result);
lengths = mysql_fetch_lengths(result);
for(int i = 0; i < num_fields; i++) {
printf("[%.*s] ", (int) lengths[i], row[i] ? row[i] : "NULL");
if (row[i]) {
//AT THIS POINT I WANT TO DO THE CONVERSION, THIS ISN'T WORKING, INCOMPATIBLE POINTER TYPE
NSArray* thisRow = [[NSArray alloc] initWithString: row[i]];
}
}
printf("\n");
}
} else {// mysql_store_result() returned nothing; should it have?
if (mysql_errno(&mysql)) {
NSLog(# "Error: %s\n", mysql_error(&mysql));
} else if (mysql_field_count(&mysql) == 0) {
// query does not return data
// (it was not a SELECT)
num_rows = mysql_affected_rows(&mysql);
}
}
}
}
[pool release];
}
Here's the revised code in case other folks are running into the same wall. Feel free to critique:
#import "AppController.h"
#include "mysql.h"
#include "unistd.h"
#implementation AppController
- (IBAction)dbConnect:(id)sender {
NSMutableDictionary* results = [[NSMutableDictionary alloc] init];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
MYSQL mysql;
mysql_init(&mysql);
if (!mysql_real_connect(&mysql, "10.1.1.99", "mysqladmin", "m3r!0n", "oldphotoarchive", 0, NULL, 0)) {
NSLog(#"%#", [NSString stringWithUTF8String:mysql_error(&mysql)]);
} else {
MYSQL_RES *result;
MYSQL_ROW row;
unsigned int num_fields;
unsigned int num_rows;
//unsigned long *lengths;
NSString* itemID = [[NSString alloc] init];
if (mysql_query(&mysql,"SELECT * FROM photorecord WHERE logNum > 10000")) {
// error
} else { // query succeeded, process any data returned by it
result = mysql_store_result(&mysql);
if (result) {
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result))) {
NSMutableDictionary* tmpDict = [[NSMutableDictionary alloc] init];
for(int i = 0; i < num_fields; i++) {
if (row[i]) {
char* cString = row[i];
NSString* dataString = [NSString stringWithCString:cString encoding:NSUTF8StringEncoding];
if ([dataString isNotEqualTo: #"NULL"]) {
//NSLog(#"%#", dataString);
if (i==0) {
itemID = dataString;
}
[tmpDict setObject: dataString forKey: [NSString stringWithFormat: #"item_%i", i] ];
}
}
}
[results setObject:tmpDict forKey:itemID];
NSLog(#"%#", results);
}
} else {// mysql_store_result() returned nothing; should it have?
if (mysql_errno(&mysql)) {
NSLog(# "Error: %s\n", mysql_error(&mysql));
} else if (mysql_field_count(&mysql) == 0) {
// query does not return data
// (it was not a SELECT)
num_rows = mysql_affected_rows(&mysql);
}
}
}
}
[pool release];
}
#end
You have to do a small bit of set up in order to get MySQL to work in your project:
Copy the two framework files libmysqlclient.a and libmysqlclient_r.a (should be in /usr/local/mysql/lib) to your project (place them in the frameworks group/folder). Include all sub folders or whatever that message is when you copy stuff in to a project.
Expand Targets, right click and then select Add->Add New Build Phase->New Copy Files Build Phase. Change destination to frameworks. This puts the two frameworks into the build of your project.
Copy the /usr/local/mysql/include folder to your project. These are the MySQL header files.
NSArray doesn't have a 'initWithString' method. .
Probably what you want is something like this...
NSString *s = [NSString alloc] initWithBytes: row[i] length: strlen(row[i]) encoding: DefaultCstring]
NSArray takes items that inherit from NSObject. You can write a simple wrapper class that has a single member of the MYSQL_ROW and pass that object into the NSArray.
Alternatively I think you could pass the MYSQL_ROW to NSString (which can be init'd from a char*) then pass the NSString to the NSArray.