Objective-C 实现链表内存释放问题

来源:4-5 从链表中删除元素

qq_叫兽_1

2018-08-04

//
//  LinkedList.h
//  ArrayList
//
//  Created by dzb on 2018/8/3.
//  Copyright © 2018 大兵布莱恩特. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface LinkedList <ObjectType> : NSObject

- (void) addObjectAtFirst:(ObjectType)object;

- (void) addObjectAtLast:(ObjectType)object;

- (void) addObject:(ObjectType)object atIndex:(NSInteger)index;

- (void) updateObject:(ObjectType)object atIndex:(NSInteger)index;

- (BOOL) containObject:(ObjectType)object;

- (ObjectType) objectAtIndex:(NSInteger)index;

- (ObjectType) removeObjectAtIndex:(NSInteger)index;

- (ObjectType) removeFirstObject;

- (ObjectType) removeLastObject;

///count
@property (nonatomic,assign) NSInteger count;
///empty
@property (nonatomic,assign,getter=isEmpty,readonly) BOOL empty;
///firstObject
@property (nonatomic,strong,readonly) ObjectType firstObject;
///lastObject
@property (nonatomic,strong,readonly) ObjectType lastObject;

@end

//
//  LinkedList.m
//  ArrayList
//
//  Created by dzb on 2018/8/3.
//  Copyright © 2018 大兵布莱恩特. All rights reserved.
//

#import "LinkedList.h"

@interface Node < ObjectType > : NSObject
///ObjectType
@property (nonatomic,strong) ObjectType object;
///next
@property (nonatomic,strong) Node <ObjectType > *next;

+ (instancetype) nodeWithObject:(ObjectType)object nextNode:(Node <ObjectType> *)next;

+ (instancetype) nodeWithObject:(ObjectType)object;

- (instancetype) initWithObject:(ObjectType)object nextNode:(Node <ObjectType> *)next;

@end

@implementation Node

+ (instancetype)nodeWithObject:(id)object {
return [Node nodeWithObject:object nextNode:nil];
}

+ (instancetype)nodeWithObject:(id)object nextNode:(Node *)next {
return [[Node alloc] initWithObject:object nextNode:next];
}

- (instancetype)initWithObject:(id)object nextNode:(Node *)next {
if (self = [super init]) {
self.object = object;
self.next = next;
}
return self;
}

- (NSString *)description {
return [NSString stringWithFormat:@"Node : %p , object : %@",self,self.object];
}


@end

@interface LinkedList ()

///head
@property (nonatomic,strong) Node *dummyHead;
///size
@property (nonatomic,assign) NSInteger size;

@end

@implementation LinkedList

- (instancetype)init
{
self = [super init];
if (self) {
self.dummyHead = [[Node alloc] init];
self.size = 0;
}
return self;
}

- (void)addObjectAtFirst:(id)object {
//	Node *node = [Node nodeWithObject:object nextNode:self.head];
//	self.head = node;
//	self.size++;
[self addObject:object atIndex:0];
}

- (void)addObjectAtLast:(id)object {
[self addObject:object atIndex:self.size];
}

- (void)addObject:(id)object atIndex:(NSInteger)index {
if (index < 0 || index > self.count) {
@throw [NSException exceptionWithName:@"LinkedList is out of bounds" reason:@"Add failed. Illegal index." userInfo:nil];
return;
}
Node *prev = self.dummyHead;
for (int i = 0; i< index; i++) {
prev = prev.next;
}
prev.next = [Node nodeWithObject:object nextNode:prev.next];
self.size++;
}


- (id)objectAtIndex:(NSInteger)index {
if (index < 0 || index >= self.count) {
@throw [NSException exceptionWithName:@"LinkedList is out of bounds" reason:@"Add failed. Illegal index." userInfo:nil];
return nil;
}

Node *cur = self.dummyHead.next;
for (int i = 0; i<index; i++) {
cur = cur.next;
}

return cur.object;
}

- (id)firstObject {
return [self objectAtIndex:0];
}

- (id)lastObject {
return [self objectAtIndex:self.count-1];
}

- (void)updateObject:(id)object atIndex:(NSInteger)index {
if (index < 0 || index >= self.count) {
@throw [NSException exceptionWithName:@"LinkedList is out of bounds" reason:@"Add failed. Illegal index." userInfo:nil];
return;
}
Node *cur = self.dummyHead.next;
for (int i = 0; i<index; i++) {
cur = cur.next;
}
cur.object = object;
}

- (BOOL)containObject:(id)object {
Node *cur = self.dummyHead.next;
while (cur != NULL) {
if ([cur.object isEqual:object])
return YES;
cur = cur.next;
}
return NO;
}


- (id) removeObjectAtIndex:(NSInteger)index {
if (index < 0 || index >= self.count) {
@throw [NSException exceptionWithName:@"LinkedList is out of bounds" reason:@"Add failed. Illegal index." userInfo:nil];
return nil;
}

Node *prev = self.dummyHead;
for (int i = 0; i<index; i++) {
prev = prev.next;
}

Node *retNode = prev.next;
prev.next = retNode.next;
retNode.next = NULL;
return retNode.object;

}
- (id) removeFirstObject {
return [self removeObjectAtIndex:0];
}

- (id) removeLastObject {
return [self removeObjectAtIndex:self.count-1];
}


- (NSInteger)count {
return self.size;
}

- (NSString *)description {

NSMutableString *string = [NSMutableString stringWithFormat:@"\nLinkedList %p : [ \n" ,self];
Node *cur = self.dummyHead.next;
while (cur != nil) {
[string appendFormat:@"%@ -> \n",cur];
cur = cur.next;
}
[string appendString:@"NULL\n"];
[string appendString:@"]\n"];

return string;
}

- (BOOL)isEmpty {
return self.count == 0;
}

- (void)dealloc
{

}
@end

测试代码 :

- (void) testArray {
	
	NSTimer *timer = [NSTimer timerWithTimeInterval:3.0f target:self selector:@selector(test) userInfo:nil repeats:NO];
	[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
	_timer = timer;
	_timeArray = [NSMutableArray array];

}

- (void) test {
	static int count = 0;
	if (count > 9) {
		[_timer invalidate];
		_timer = nil;
		NSLog(@"time is %@",[_timeArray valueForKeyPath:@"@avg.self"]);
		return;
	}

	dispatch_async(dispatch_get_global_queue(0, 0), ^{
		CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
		int number = 100000;
		Person *p = [Person new];
		LinkedList <Person *> *linked = [[LinkedList alloc] init];
		for (int i = 0; i<number; i++) {
			[linked addObjectAtFirst:@(i)];
		}
		NSLog(@"%@",linked);
		CFAbsoluteTime linkTime = (CFAbsoluteTimeGetCurrent() - startTime);
		CFTimeInterval duration = linkTime * 1000.0f;
		NSLog(@"Linked in %f ms",duration);
//		self->_linkedList = linked;
		[self->_timeArray addObject:@(duration)];
		count++;
	});
	
}


当链表添加元素个人超过800时候 发现打印链表时候数据有丢失 比如添加1...800  打印只有100...800 ,前边的0-99 数据不见了. 当添加超过800个元素时候 会出现内存释放问题 ,我的猜测时当没有强引用指向这个链表时候 ,同时对大量的对象 release 时候出错了.  

由于实在找不到原因,只能是猜测链表内部节点在释放内存时候出了问题. 于是我将链表内部的 Node 由对象改成 C 语言 结构体

typedef id AnyObject;

typedef struct node {
	__unsafe_unretained AnyObject data;
	struct node *next;
} Node; 

改进后的链表内存释放改为手动释放内存,没有发现节点数据丢失和内存释放的问题.
希望波波老师有时间把我上边 Objective-C 实现的链表代码 运行下, 可能 Java 是自动管理内存吧,在学习动态数组时候 没有见波波老师释放过内存,我自己写的动态数组 也是用的 C 语言数组,然后手动管理存入数组的对象内存引用计数.


写回答

1回答

liuyubobobo

2018-08-04

抱歉,我已经超过5年不写OC了,看不动OC代码了。。。


这个课程讲数据结构原理,视频语言是Java语言。请允许我不能帮助所有同学用任意语言实现的代码调程序。。。望谅解。


抱歉。加油!:)

0
1
qq_叫兽_1
波波老师 我用 C 语言的结构体指针完成的链表实现 能够有效的管理 OC 引用计数 但是整体实现思路还是跟着波波老师讲的一样的. 虽然有点小郁闷 但是不影响最终实现的功能
2018-08-05
共1条回复

玩转数据结构

动态数组/栈/队列/链表/BST/堆/线段树/Trie/并查集/AVL/红黑树…

6221 学习 · 1704 问题

查看课程