自动内存管理可分为静态管理和动态管理,编译原理书上说的是动态管理,即运行时的自动垃圾回收(gc)。作者认为垃圾这个词不雅,就换用了“自动内存管理”。静态管理的关键是,在编译阶段自动添加free函数。

静态管理能处理多数情况,少数不能处理的情况,交给动态管理,即运行时自动垃圾回收(gc)处理。

程序结构分为顺序、分支、循环。分别讨论。

1、顺序结构

在顺序结构的程序中,从p=malloc到use§画出生命线,如果有q=p,也要画出到use(q)的生命线。

p=malloc(100)
q=p
use(p)
//这里不能free(p),后边还要用到p的等价变量q
use(q)
//在这里free(p),因为p和q等价,free(q)也行

关于q=p有三种解释:
一、指针赋值

object* p=malloc(100)
object* q=p

二、内存块复制

memcpy(q,p,100)

三、对象复制
包括p的成员一起复制。如p有一个长度为20的成员。

memcpy(q,p,100)
memcpy(q.m,p.m,20)

制作指针p的等价变量,用的是第一个,指针赋值。

p=malloc(100)
use(p)
//在这里free(p),因为p即将被赋予新的值
p=malloc(50) //这个p是个新的变量
use(p)
//free(p)

在函数调用中,如果有return p,说明对应的内存块还要继续使用,不能free。

object* func()
{
p=malloc(50)
use(p)
return p
}

生命线画到调用func的那个函数里。

2、分支结构

在分支结构中,生命线要分别进入不同的分支。

p=malloc
if rand()>0.5use(p)
elsenot use(p)
//如果在之后没有use(p),就在分支内添加free(p)。

分支内部的,按顺序结构处理。分支还会结束,当分支结束后继续use的情况,在最后一次之后free

if a>0p=mallocuse(p)
elseq=mallocuse(q)//free(q),在这里释放q,和顺序结构中一样q=mallocuse(q)//free(q)
use(p)
not use(q)
//free(p)

3、循环结构

在循环结构中分配的内存,相当于顺序结构中的连续多个p=malloc,需要free。

for(i=0;i<2;i++)
{p=mallocuse(p)
}

这个循环相当于

p=malloc
use(p)
p=malloc
use(p)

与顺序结构中一样,需要free(p),具体怎样进行呢?有两种方案:
一、在循环体结束前free

for(i=0;i<2;i++)
{
p=malloc
use(p)
//free(p)
}

这是常规思路,但有时,需要在循环结束后继续使用循环体中的变量,这需要另一种方案:
二、在malloc之前free

for(i=0,p=NULL;i<2;i++)
{if(p!=NULL)free(p)p=mallocuse(p)
}
use(p)

这样一来,就能够在循环结束后继续use(p)了。

4

除了跟踪malloc的生命线,还可以跟踪变量的生命线。一种有意思的情况是,两个变量可以共用一块内存。如int和float都占4字节,某种情况下,它们共用4字节空间。

int a
float b
b=use(a)

这种情况下,a和b可共用一块内存,因为a和b的生命线并不重合。b=use(a)可以理解成对a进行一系列计算,并把结果保留到b中,以后也不再使用a了。这样一来,可以先释放a再分配b,又因为a和b大小相等,就成了它们两个共用一块内存了。

int a
t=use(a)
//释放a
float b //在这里分配b
b=t

5

对malloc和free的封装函数,需要给出源代码,或是给出描述文件,方便内存管理。

p=start()   //封装了malloc
use(p)
end(p)     //封装了free

如果不能自动添加封装了free的end函数,就只能靠gc了。
如果有start函数的源代码,当然可以追踪到malloc的调用情况。如果没有源代码,就需要描述文件,它应该是这样的:

start():p=mallocp.left=mallocp.right=malloc

有了函数的描述文件,就能在需要free(p)的时候,也能够自动调用free(p.left)free(p.right)。以前这需要手动写end(p),现在可以自动地执行这些了。

6

如何处理环状结构?

a=malloc
b=malloc
a.m=b
b.m=a

这道题出现在python的引用计数法,需要说明的是,python的del和C语言的free并不相同。del使得引用计数减一,如果为零就回收。free必然回收一块内存,对已经回收了的空间再次使用free将报错。
上述例子中,执行del a和del b后,两个内存块仍然存在。若执行free(a),需连带执行free(a.m),此时再次执行free(b)将报错。
看来,画张图是必须的,因为实际情况中,不会是这么简单的环状结构。

7

最简单的情况是顺序结构:

p=malloc
use(p)
//生命线延续至此,自动添加free(p)

更复杂的情况是:
一、指针被重新赋值

p=malloc
p=malloc

第二句给p赋予新的值,那么原始的值就丢失了,应该在此之前free掉旧的内存块:

p=malloc
free(p)  //这句是自动添加的
p=malloc

二、指针被复制给新的指针

p=malloc
q=p
use(p)
use(q)

q看作是p的等价指针,生命线延续到不再使用p和q之后。

p=malloc
q.m=p

q是一个结构体,或称作对象,这是指针复制的另一种形式。
一个简单的函数调用,相当于顺序结构。

main()
{p=mallocp=func(p)
}
func(o)
{use(o)return o
}

调用函数的过程隐含一个o=p,如上文,生命线要延续下去,直到不再使用o。又因为return o隐含一个p=o,所以,生命线继续延续到p之后。

8

比顺序结构复杂的,是分支结构和循环结构。从汇编语言层次分析,是cmp和jmp指令的组合。
jmp指令明显可以指定生命线的方向,或者说,生命线沿着jmp的方向而延续。
if(a>0){B}else{C}
这段C语言转换成汇编语言:

cmp a,0
jbe A10;小于等于时,跳转到C
{B}
A10:
{C}

因为跳转指令的存在,生命线覆盖了{B}和{C},并进一步延伸到C以后。

对于循环结构,有如下代码:
for(i=0;i<10;i++){B}
转换成汇编语言:

mov i,0
A20:
cmp i,10
jge A10
{B}
inc i
jmp A20
A10:
;后续代码

这段代码怎么读?若在{B}中包括malloc,那么生命线怎样延续?如果指针p在for循环之前出现,那么它的作用域可以延伸到for循环之后;如果指针p在语句块{B}内部出现,则它只延续到B结束。

p
for(...){...}
use(p)//这里可以使用pfor(...){
p
use(p)
}
//这里不能使用p

前文中的关于jmp指令对于生命线的延续问题,在这里并不存在。应该从C语言的层次考虑生命线,在汇编语言层次,规律不明显。

用生命线的方法处理malloc和指针变量。其中指针变量又包括p和o.m,有了p=malloc之后,p就是malloc的等价变量,这和q=p使q,p等价是一样的。

{p   //p是这个作用域中的变量func(p)use(p)
}//在这里清除p,这是变量的作用域。

变量的作用域结束后,连带的malloc也就需要free了。但由于一个malloc可以有多个指针,所以画张图出来描述它们之间的关系,是必不可少的。

9

关于函数的递归调用还没研究,在递归调用中,生命线呈现什么样子?似乎是这样的:递归调用的函数会在栈上留下痕迹,每调用一次就在栈上分配出一个“栈帧”,然后便是函数调用时传递参数的复制过程。对于复制过程导致的生命线变化前文已经讨论过了。

func(x)
{
y=use(x)
func(x)
}

这是一个递归调用。

函数的调用,需要处理好传参数和返回值,这是两个赋值操作,其他方面,没什么不同?

自动内存管理(gc),新的思路相关推荐

  1. oracle11g自动内存管理好吗,Oracle11G新特性的研究之【自动内存管理】

    让实例运行为自动内存管理模式下 SQL> show parameter sga NAME                                 TYPE        VALUE -- ...

  2. 【Java书笔记】:《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》第2部分-自动内存管理,第3部分-虚拟机执行子系统,第5部分-高效并发

    作者:周志明 整理者GitHub:https://github.com/starjuly/UnderstandingTheJVM 第2部分-自动内存管理 第2章 Java内存区域与内存溢出异常 2.2 ...

  3. 读书笔记——深入理解JVM(JVM自动内存管理)

    简介 本系列为<深入理解Java虚拟机-JVM高级特性与最佳实践>一书的阅读笔记. 本书开头介绍了JVM发展的历史,接着介绍了JVM是如何实现自动内存管理的. 本章节主要介绍: JVM的存 ...

  4. 深入理解java虚拟机-1.自动内存管理

    文章目录 1.自动内存管理 1.1 Java内存区域与内存溢出异常 1.1.1 运行时数据区域 程序计数器 程序计数器为什么是私有的? java虚拟机栈 本地方法栈 虚拟机栈和本地方法栈为什么是私有的 ...

  5. 一、JAVA虚拟机------JVM自动内存管理

    JVM自动内存管理 一.JAVA内存区与内存溢出 1.1 概述 1.2 运行时数据区 1.2.1 程序计数器 (Program Counter Register) 1.2.2 Java虚拟机栈(Jav ...

  6. c++堆内存默认大小_Java 自动内存管理

    Java 与 C.C++ 最大的区别在于内存管理方面. 对于 C.C++来说, 在内存管理方面,既拥有每个对象的"所有权",又担负着每个对象生命从开始到终结的维护责任. 而对 Ja ...

  7. 【JVM高级特性与最佳实践(第3版)-周志明】-学习记录之【自动内存管理】

    写在前面,不是原创,是周志明老师书里得内容,方便个人随时学习查看,因为发布得时候没有这个选项,只能选原创 一.概述 对于Java程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要为每一个new操作 ...

  8. [翻译]理解Unity的自动内存管理

    当创建对象.字符串或数组时,存储它所需的内存将从称为堆的中央池中分配.当项目不再使用时,它曾经占用的内存可以被回收并用于别的东西.在过去,通常由程序员通过适当的函数调用明确地分配和释放这些堆内存块.如 ...

  9. 2 自动内存管理机制(一)运行时数据区域、垃圾回收算法和垃圾回收器

    文章目录 自动内存管理机制(一)运行时数据区域.垃圾回收算法和垃圾回收器 运行时数据区域 垃圾收集算法(方法论) 垃圾收集器(具体实现) 附录 响应时间和吞吐量 参考 自动内存管理机制(一)运行时数据 ...

最新文章

  1. 【数据结构练习习题】java实现版(一)
  2. 【已解决】请先调用 init 完成初始化后再调用其他云 API。init 方法可传入一个对象用于设置默认配置,详见文档。; at cloud.callFunction api 解决方案
  3. matlab无刷双馈电机模型搭建,基于MATLAB的无刷双馈电机建模与仿真
  4. python安装request库_Python——安装requests第三方库
  5. 双侧检验的p值和单侧检验_【单侧检验和双侧检验的区别】_怎么检验_如何检验-大众养生网...
  6. NW.js 简介与使用
  7. java collection_【基础篇】java-Collection集合-List和Set
  8. 免费学plc的手机app_PLC网校app手机版 v1.2
  9. 易虎再谈网站被恶意刷流量和防恶意点击的解决思路
  10. GoFW|网页加速器
  11. python遇到错误跳过_python如何设置报错跳过?
  12. 数学建模——公交调度优化
  13. 英语学(xiao 二声)习__字母读音
  14. kdj值应用口诀_KDJ指标应用口诀
  15. 1677 treecnt(贡献)
  16. MT4平台上mql4实现的基于macd指标的智能交易EA
  17. svg 读取SVG文件并绘制矩形框选择图元
  18. 自媒体淘客到底要怎么做
  19. iPhonexr安兔兔html5测试,iPhone XR 安兔兔跑分出炉!竟与 iPhone XS 相差无几
  20. 校门外的树(三种解法,非直接暴力)

热门文章

  1. MessageBox、MessageBeep、Beep 和 messagedlg用法
  2. #14# SCCM管理 - 维护窗口
  3. python游戏开发工程师证书_【网易游戏游戏开发工程师面试】网易python开发 游戏公共支持-看准网...
  4. hdu--2669Romantic
  5. lisp获取图名_amp;#65279;如何用autolisp获取cad图形文件中直线和多义线的图层名 - 易采站长站...
  6. js怎么给下拉框默认选中
  7. 手机dirac是什么_刚刚发布的一加 6T旗舰手机采用Dirac技术
  8. MSSTDFMT.dll系统文件(附2种MSSTDFMT.dll 注册方法)-系统增强
  9. 曾经和人谈到情,句句不离你
  10. python做的如何给别人用流量_流量怎么共享给别人用