底层内存管理

在现代开发中,几乎很少有人关注内存的消耗,因为这得益于当下计算机的高速发展,相比于以前来说,内存不论在容量上面还是效率上面都大大提高,并且在Java层面上更是有JVM对垃圾内存的释放,使得人们从管理内存的工作中得以解放。但是这就导致一个问题,如果不直接去释放一些内存,往往实现一个简单功能会被加载大量无用的内存,导致内存急剧增加。而用不能很好的释放这些内存,导致内存泄漏。因此本文将从Free Pascal(以下用FPC代替),介绍如何在底层来管理好内存。

ISCFPC介绍

在这里很感谢何老师所开发的ISCFPC,这个是开发Free Pascal的一个脚手架,可以通过

iscfpc create web demo  # 创建一个web项目
iscfpc build # 构建项目
iscfpc doctor # 检查Free Pascal 的环境
iscfpc ocean # 一些示例项目
iscfpc upgrade # 在线升级基础库

通过上面的命令可以很轻松创建一个FPC项目出来。

指针,引用,内存

首先要知道什么是内存,在我的理解里面内存简单来说就是直接被cpu访问的地址,这些地址在总是可以直接被mov到的,而不需要转换,所以数据存在内存里,比数据存在磁盘上面要快,但是内存里面的数据在断电后,在内存里面的数据也将不见。

引用:引用是一个变量,它存在的意义是为了方便我们找到内存,如果没有引用我们访问内存就只能带着0x00004000 这样的直接地址,导致不得不记忆大量的16进制地址。

空引用:如果一个引用仅仅只是声明,但是没有指向一个内存那这个引用就是空引用。

指针:指针本质来说是一个变量,但是这个变量里面的存储的是一个地址,也就是说指针里面可以存储一个地址,指向一个内存

空指针:指针里面的地址,所指引用的内存为空,就是空指针。

指针和引用都是为了方便指向内存,在Free Pascal中指针和引用可以相互转换,引用的地址就是指针,解指针就是引用。例如:

type 
	PStr = ^string;
var P :PStr;
	  Str:string;
begin
	Str := 'demo';
	P := @Str;
	WriteLn(Str);
	WriteLn(P^); 
end;	   

内存管理

在底层语言开发中,我们永远都是内存管理的奴隶,一不小心就会造成内存泄漏,或者内存过渡释放。首先要清楚什么东西我们要释放,在FPC中只有指向内存的指针或者引用需要释放内存,如果这个是基本类型包含String,或者空指针,空引用,那么这个变量就不需要被释放。
那什么又是指向内存的指针或引用呢?在FPC中简单来说,就是引用或者指针是否被Create过,果然被Create过,这个引用就指向了一个新的内存空间,没有则是空指针或者引用。下面举例说明:

// 定义三个容器
type
	TMapString = specialize TISCMap<string,string>;
    TListMapString = specialize TISCList<TMapString>;  
var FMap:TMapString;
	 FListMap:TListMapString;
	 i : Interger;
begin
	FMap:=TMapString.Create;
	FListMap := TListMapString.Create;
	FListMap.Add(FMap);
    // 释放内存的方案
    // 1
    FMap.Free;
    FListMap.Free;
   
   // 2
   FMap.Free;
   for i := FListMap.Count -1 downto 0 do begin 
        FListMap[i].Free;
   end; 
   FListMap.Free;
   
   // 3
    for i := FListMap.Count -1 downto 0 do begin 
        FListMap[i].Free;
   end; 
   FListMap.Free;
end.

这三种方案中可以发现,1,3的释放本质上是一样的,这就说明了在add方法中没有内存被创造,只是创造了一个指针指向FMap的内存,也就是说这里有多次指针指向同一个内存,如果像2处释放,肯定汇报空指针错误,因为指针所指内存已经被释放了 ,因此用2方法表明Add方法中有新内存被创建,List里面的指针指向新内存,所以要释放两次内存,查阅Add实现源码,可以发现这个是指针的拷贝,没有进行内存拷贝,所以用1,3方法即可。

内存管理建议

好的编码习惯会让事情轻松百倍,特别是内存管理的过程中,不然会一不小心造成内存泄漏或者过度释放。在我最近的开发中,所探索的出的建议是:尽可能的保证一个孤立的设计,这句话说,尽可能保证在类的设计,procedure的设计,function的设计不Create内存,也不Free内存,保证里面的Create与Free 总是成对出现的。
对于Class来说:

type 
 { TDemo }

 TDemo = class(TObject)
	private
	  FMap:TMapString;
	  FListMap:TListMapString;
	public
	   constructor Create;
           destructor Destroy;override;
           procedure DoSomething(AMap:TMapString);
	end;

implementation

{ TDemo }

constructor TDemo.Create;
begin
    FMap := TMapString.Create;
    FListMap:=TListMapString.Create;
end;

destructor TDemo.Destroy;
begin
  FMap.Free;
  for i := FListMap.Count -1 downto 0 do begin
        FListMap[i].Free;
  end;
  FListMap.Free;
  inherited Destroy;
end;

procedure TDemo.DoSomething(AMap: TMapString);
begin
   AMap.Add('add','demo');
end; 

请尽量不要在在类的里面procedure或者 function释放掉类全局变量。采用这样的方法最大的好处,一个对象的Create与Free总是在一个地方成对出现。比如上面的对象调用为:
··· pascal
var demo:TDemo;
map:TMapString;
begin
demo := TDemo.Create;
map : = TMapString.Create;
demo.DoSomething(map);
WriteLn(PrintMap(map));
map.Free;
demo.Free;
end.
···
同时在function里面尽量不要返回对象,这样的情况尽可能的用procedure来为一个对象里面填充数据,如上面的DoSomething,function 尽量只返回一些基本类型。

结语

本文介绍了内存与指针引用的概念,同时指出什么样的内存该被回收,并且结合最近实战开发,给出了一些编码上面的建议,以此来避免内存泄漏或者过度回收的问题。内存管理一直以来都是程序优化的头等问题,希望我可以以此抛砖引玉来有着更多优质的内存管理方案。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

myenjoy_1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值