我有一个简单的Cocoa程序来绘制从基于Raspberry Pi的服务器读取的数据。几千次读取后,程序内存使用量将推向1 GB。每次读取只是获得一个长整数的时间和浮点值表示从温度传感器读取的温度。我已经删除了一些我能想到的可能利用内存的问题并且问题没有改变。请告诉我我的问题在哪里。
//
// ABSAppDelegate.m
// RPi_socket_test
//
#import "ABSAppDelegate.h"
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
@implementation ABSAppDelegate
- (void)dealloc
{
[super dealloc];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
NSView *superview = [[self window] contentView];
NSRect fullPlotFrame = [[self window] frame];
fullPlotFrame.size.height *= 0.75;
fullPlotFrame.size.width *= 0.85;
fullPlotFrame.origin.x = [[self window] frame].size.width*0.1;
fullPlotFrame.origin.y = [[self window] frame].size.height*0.02;
thePlot = [[[RPiViewController alloc] initWithFrame:fullPlotFrame] retain];
[superview addSubview:thePlot];
[thePlot display];
[NSThread detachNewThreadSelector:@selector(getTemp) toTarget:self withObject:nil];
}
-(void)getTemp{
int sockfd = 0, n = 0;
char recvBuff[1024];
struct sockaddr_in serv_addr;
while(ok){
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
memset(recvBuff, '0',sizeof(recvBuff));
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
NSLog(@"\n Error : Could not create socket \n");
ok = false;
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5001);
if(inet_pton(AF_INET, "172.27.220.44", &serv_addr.sin_addr)<=0)
{
NSLog(@"\n inet_pton error occured\n");
}
if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
NSLog(@"\n Error : Connect Failed \n");
ok = false;
}
while ( (n = (int)read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0)
{
recvBuff[n] = '\0';
[self performSelectorOnMainThread:@selector(displayTemp:) withObject:[NSString stringWithFormat:@"%.18s", recvBuff] waitUntilDone:YES];
}
if(n < 0)
{
NSLog(@"\n Read error \n");
}
close(sockfd);
sleep(1);
[pool drain];
}
}
-(void)displayTemp:(NSString*)theData{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSPoint pointForConversion = NSPointFromString(theData);
[txtTempC setStringValue:[NSString stringWithFormat:@"%0.0f, %0.2f", pointForConversion.x, pointForConversion.y]];
long int dataSize = [thePlot SizeOfData];
if(dataSize < 1024) [txtSizeOfData setStringValue:[NSString stringWithFormat:@"%i Bytes", (int)dataSize]];
else if(dataSize < 1024*1024) [txtSizeOfData setStringValue:[NSString stringWithFormat:@"%0.3f kBytes", (float)dataSize/1024]];
else [txtSizeOfData setStringValue:[NSString stringWithFormat:@"%0.3f MBytes", (float)dataSize/(1024*1024)]];
[thePlot addDataToPlot:pointForConversion];
[thePlot display];
[[self window] display];
[pool drain];
}
-(IBAction)getTemp:(id)sender{
if(!ok){
ok = true;
[NSThread detachNewThreadSelector:@selector(getTemp) toTarget:self withObject:nil];
}
}
-(IBAction)stopClient:(id)sender{
ok = false;
}
-(void)controlTextDidChange:(NSNotification *)obj{
if([obj object] == txtMax) [thePlot setMaxRawPlotData:(int)[txtMax integerValue]];
}
@end
使用视图控制器
//
// RPiViewController.m
// RPi_socket_test
//
#import "RPiViewController.h"
@implementation RPiViewController
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
fontSize = 10;
NSMutableDictionary *drawStringAttributes = [[NSMutableDictionary alloc] init];
[drawStringAttributes setValue:[NSColor blackColor] forKey:NSForegroundColorAttributeName];
NSFont *myFont = [NSFont fontWithName:@"American Typewriter" size:fontSize];
[drawStringAttributes setValue:myFont forKey:NSFontAttributeName];
NSString* strLabelWidth = [NSString stringWithFormat:@"%0.2f", 55.55];
float labelWidth = [strLabelWidth sizeWithAttributes:drawStringAttributes].width;
NSRect frameForData = [self bounds];
frameForData.origin.x += labelWidth;
frameForData.size.width -= labelWidth;
myPlot = [[[RPiView alloc] initWithFrame:frameForData] retain];
[self addSubview:myPlot];
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect
{
// Drawing code here.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSPoint minPoint = [myPlot findMinValues];
NSPoint maxPoint = [myPlot findMaxValues];
NSMutableDictionary *drawStringAttributes = [[NSMutableDictionary alloc] init];
[drawStringAttributes setValue:[NSColor blackColor] forKey:NSForegroundColorAttributeName];
NSFont *myFont = [NSFont fontWithName:@"American Typewriter" size:fontSize];
[drawStringAttributes setValue:myFont forKey:NSFontAttributeName];
NSString* MinTempLabel = [NSString stringWithFormat:@"%0.2f", minPoint.y];
NSPoint pointToDrawLabel = {0,0};
[MinTempLabel drawAtPoint:pointToDrawLabel withAttributes:drawStringAttributes];
NSString* MaxTempLabel = [NSString stringWithFormat:@"%0.2f", maxPoint.y];
pointToDrawLabel.y = [self bounds].size.height - [MaxTempLabel sizeWithAttributes:drawStringAttributes].height;
[MaxTempLabel drawAtPoint:pointToDrawLabel withAttributes:drawStringAttributes];
[pool drain];
}
-(void)addDataToPlot:(NSPoint)theDataToPlot{
[myPlot addDataToPlot:theDataToPlot];
}
-(long int)SizeOfData{
long int dataSize = [myPlot SizeOfData];
return dataSize;
}
-(int)setMaxRawPlotData:(int)theMax{
return [myPlot setMaxRawPlotData:theMax];
}
@end
和子视图控制器
//
// RPiView.m
// RPi_socket_test
//
#import "RPiView.h"
@implementation RPiView
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
maxRawPlotData = 3600;
firstRawPlotIndex = 0;
dataCount = 0;
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect
{ // Drawing code here.
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSPoint minPoint = [self findMinValues];
NSPoint maxPoint = [self findMaxValues];
float xScale = ([self bounds].size.width)/(maxPoint.x - minPoint.x);
float yScale = [self bounds].size.height/(maxPoint.y - minPoint.y);
[[NSColor whiteColor] set];
NSRect fillArea = [self bounds];
[NSBezierPath fillRect:fillArea];
NSBezierPath *pathForPlot = [[NSBezierPath alloc] init];
if(dataCount<maxRawPlotData){
if(dataCount>1){
NSPoint p1 = myData[0];
p1.x = (p1.x-minPoint.x)*xScale;
p1.y = (p1.y-minPoint.y)*yScale;
[pathForPlot moveToPoint:p1];
}
for(int i=1; i<dataCount; i++){
NSPoint p = myData[i];
p.x = (p.x-minPoint.x)*xScale;
p.y = (p.y-minPoint.y)*yScale;
[pathForPlot lineToPoint:p];
}
}
else{
unsigned long firstPointToPlot = dataCount-maxRawPlotData;
NSPoint p1 = myData[firstPointToPlot];
xScale = [self bounds].size.width/maxRawPlotData;
minPoint.x = p1.x;
p1.x = (p1.x-minPoint.x)*xScale;
p1.y = (p1.y-minPoint.y)*yScale;
[pathForPlot moveToPoint:p1];
for(unsigned long i=firstPointToPlot; i<dataCount; i++){
NSPoint p = myData[i];
p.x = (p.x-minPoint.x)*xScale;
p.y = (p.y-minPoint.y)*yScale;
[pathForPlot lineToPoint:p];
}
}
[[NSColor blackColor] set];
[pathForPlot stroke];
[pool drain];
}
-(void)addDataToPlot:(NSPoint)theDataToPlot{
myData[dataCount] = theDataToPlot;
dataCount++;
}
-(NSPoint)findMaxValues{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSPoint maxValue = {-1e9, -1e9};
for(int i=0; i<dataCount; i++){
NSPoint testValue = myData[i];
if(testValue.x > maxValue.x) maxValue.x = testValue.x;
if(testValue.y > maxValue.y) maxValue.y = testValue.y;
}
[pool drain];
return maxValue;
}
-(NSPoint)findMinValues{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSPoint maxValue = {1e9, 1e9};
for(int i=0; i<dataCount; i++){
NSPoint testValue = myData[i];
if(testValue.x < maxValue.x) maxValue.x = testValue.x;
if(testValue.y < maxValue.y) maxValue.y = testValue.y;
}
[pool drain];
return maxValue;
}
-(long int)SizeOfData{
long int dataSize = 0;
for(int i=0; i<dataCount; i++){
dataSize += sizeof(NSPoint);
}
return dataSize;
}
-(int)setMaxRawPlotData:(int)theMax{
if(theMax<10) theMax = 10;
maxRawPlotData = theMax;
return (int)dataCount;
}
@end
答案 0 :(得分:0)
因此,在逐节关闭代码后,我跟踪了子视图控制器中drawRect方法的泄漏。通过在任何地方添加NSAutoreleasePools并释放NSBezierPath,泄漏被堵塞。
感谢您给我一个“大声思考”的出路!
- (void)drawRect:(NSRect)dirtyRect
{ // Drawing code here.
NSAutoreleasePool* uberpool = [[NSAutoreleasePool alloc] init];
NSPoint minPoint = [self findMinValues];
NSPoint maxPoint = [self findMaxValues];
float xScale = ([self bounds].size.width)/(maxPoint.x - minPoint.x);
float yScale = [self bounds].size.height/(maxPoint.y - minPoint.y);
[[NSColor whiteColor] set];
NSRect fillArea = [self bounds];
[NSBezierPath fillRect:fillArea];
NSBezierPath *pathForPlot = [[NSBezierPath alloc] init];
if(dataCount<maxRawPlotData){
if(dataCount>1){
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSPoint p1 = myData[0];
p1.x = (p1.x-minPoint.x)*xScale;
p1.y = (p1.y-minPoint.y)*yScale;
[pathForPlot moveToPoint:p1];
[pool drain];
}
for(int i=1; i<dataCount; i++){
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSPoint p = myData[i];
p.x = (p.x-minPoint.x)*xScale;
p.y = (p.y-minPoint.y)*yScale;
[pathForPlot lineToPoint:p];
[pool drain];
}
}
else{
unsigned long firstPointToPlot = dataCount-maxRawPlotData;
NSPoint p1 = myData[firstPointToPlot];
xScale = [self bounds].size.width/maxRawPlotData;
minPoint.x = p1.x;
p1.x = (p1.x-minPoint.x)*xScale;
p1.y = (p1.y-minPoint.y)*yScale;
[pathForPlot moveToPoint:p1];
for(unsigned long i=firstPointToPlot; i<dataCount; i++){
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSPoint p = myData[i];
p.x = (p.x-minPoint.x)*xScale;
p.y = (p.y-minPoint.y)*yScale;
[pathForPlot lineToPoint:p];
[pool drain];
}
}
[[NSColor blackColor] set];
[pathForPlot stroke];
[pathForPlot release];
[uberpool drain];
}