栈,堆,GC算法

栈(Stack)

什么是栈

是一种后入先出(LIFO)数据结构,只能在一端对数据项进行插入和删除这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。栈内存主管程序的运行,生命周期和线程同步,线程结束,栈内存就释放

栈中存放什么

8大基本类型(byte short int long double float boolean char),对象的引用,实例的方法

栈帧(Stack Frame)

栈帧转自:知乎

  • 栈帧是用来支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区中的虚拟机栈的栈元素。
  • 栈帧存储了方法的局部变量表、操作数栈、动态连接、和方法返回地址、额外的附加信息。
  • 每个方法在执行的同时,都会创建一个栈帧。每一个方法从调用开始至执行完成的过程,都对应着一个栈帧在虚拟机栈里面从入栈到出栈的过程。
当前栈帧(Current Stack Frame)

一个线程中的方法调用链可能会很长,很多方法都同时处于执行状态。对于执行引擎来说,在活动线程中,只有位于栈顶的栈帧才是最有效的,称为当前栈帧,与这个栈帧相关联的方法称为当前方法。执行引擎运行的所有的字节码指令都只针对当前栈帧进行操作。在概念模型上,典型的栈帧结构图如下:

局部变量表

局部变量表(Local Variable Table)是一组变量值存贮空间,用于存放方法参数方法内定义的局部变量

操作数栈

操作数栈(operand Stack)也常称为操作栈,它是一个后入先出栈。当一个方法刚刚开始执行的时候,这个方法的操作数栈是空的,在方法执行的过程中,会有各种字节码指令往操作数栈中写入和提取内容,也就是出栈 / 入栈操作。例如,在做算术运算的时候是通过操作数栈来进行的,又或者在调用其它方法的时候是通过操作数栈来进行参数传递的。

动态连接

每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接(Dynamic Linking)。

Class文件的常量池中存在大量符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用作为参数,这些符号引用一部分在类加载阶段中的解析阶段会转为直接引用,这种转化也称为静态解析。另外的一部分将在每一次运行时期转化为直接引用。这部分称为动态连接。

方法返回地址

当一个方法开始执行后,只有2种方式可以退出这个方法 :

方法返回指令 : 执行引擎遇到一个方法返回的字节码指令,这时候有可能会有返回值传递给上层的方法调用者,这种退出方式称为正常完成出口。

异常退出 : 在方法执行过程中遇到了异常,并且没有处理这个异常,就会导致方法退出。

无论采用任何退出方式,在方法退出之后,都需要返回到方法被调用的位置,程序才能继续执行,方法返回时可能需要在栈帧中保存一些信。用来帮助恢复它的上层方法的执行状态。

方法退出的过程实际上就等于把当前栈帧出栈,因此退出可能执行的操作有:
1.恢复上层方法的局部变量表和操作数栈
2.把返回值(如果存在返回值)压入调用者栈帧的操作数栈中
3.调整PC计数器的值以指向方法调用指令后面的一条指令

堆(Heap)

什么是堆

Java 中的堆是 JVM 所管理的最大的一块内存空间,主要用于存放各种类的实例对象。堆主要由新生代老年代组成
新生代又分为伊甸园区,幸存区,老年区

GC算法

什么是GC

GC即垃圾回收,当一个对象无用时(没有被引用到的对象),虚拟机就会清除其所占用的内存空间

GC分为轻GC(Minor GC)和重GC(Major GC/Full GC)

  • 轻GC:回收新生代的垃圾
  • 重GC:新生代和老年代的垃圾都回收
轻GC()

首先,将任何新对象分配到Eden空间。两个幸存区开始都是空的。当伊甸园空间填满时,将触发轻要垃圾回收。未被回收的对象将从伊甸园区被移到幸存区(from),此时对象的年龄+1,当下一次GC时,伊甸园区还是同样清除未被引用的对象,将未被回收的对象移动到另外一个幸存区(to),第一个幸存区(from)未被清除的对象也会移动到幸存区(to),此时从伊甸园区来的对象年龄是1,从第一个幸存区(from)来的年龄是2,此时第一个幸存区(from)的是空的,在下一次GC时,伊甸园区的未被清除的对象将移到幸存区(to[上次的from]),年龄为1.幸存区(from[上次的to])的未被清除的对象也将移动到幸存区(to[上次的from]),年龄都+1,此时幸存区(to[上次的from])有不同年龄的对象,此时幸存区(to[上次的from])变成空的了.当进行轻GC的对象年龄为15(默认,可自行设置)时,此对象进入老年区

每进行一次GC幸存区会有一个是空的,空的幸存区就是to,当空间内存不足时,对象也会移到下一区域

重GC()

新生代和老年代的垃圾都回收,先进行轻GC清除新生代未被引用的对象,然后再清除老年代未被引用的对象

引用计数法

给每个对象添加一个计数器,每当有一个地方引用它时,计数器就加1;当引用失效时,计数器就减1;当计数器为0时就清除对象

优点:

  • 可即时回收垃圾(每个对象始终知道自己是否有被引用,当被引用的数值为0时,对象马上可以把自己当作空闲空间链接到空闲链表)
  • 最大暂停时间短(进行GC时,用户线程会被进入等待,等待GC完再继续执行)
  • 没有必要沿着指针查找

缺点:

  • 每个对象都要分配计数器,浪费内存空间
  • 每次引用都要进行加减运算,影响性能
  • 循环引用无法回收

Java一般不使用这个算法

复制法

将空间平均分为2份,每次只使用其中一块,进行GC时,将使用那块存活的对象全部复制到另一块并进行排序,然后将使用的那块的对象全部清除,并且更新引用对象的引用地址

优点:

  • 不会发生碎片化
  • 吞吐量优秀

缺点:

  • 浪费内存,每次只使用一半内存
  • 每次GC都要更新引用地址

标记清除压缩法

标记-清除
进行堆扫描,将被引用的对象进行标记,再扫描一次,将没有引用的对象进行清除

优点: 不需要额外的空间

缺点:

  • 要扫描两次,浪费时间
  • 空间内存不连续,内存碎片化

标记-压缩
标记-清除一样,只是在清除后再扫描一次,进行整理,将活着的对象向一端移动

优点:

  • 对象有序
  • 不需要额外的空间

缺点:

  • 要扫描三次,更浪费时间
  • 需要更新引用地址

总结

内存效率: 复制算法 > 标记清除算法 > 标记压缩算法 (时间复杂度)

内存整齐度: 标记压缩算法 = 复制算法 > 标记清除算法

内存利用率: 标记压缩算法 > 标记清除算法 > 复制算法

分代收集算法

新生代: 存活率低,使用复制算法
老年代: 区域大,存活率高,使用标记清除 + 标记压缩算法


个人拙见,如有错误望指出
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值