java 全局变量 内存不回收_JAVA知识梳理:内存管理与垃圾回收机制

相对于C,C++来说,java程序员最幸运的事就是不用进行内存控制,很少会出现内存溢出的异常。但是这也不是绝对的,当出现oom的时候,如果不了解虚拟机是如何使用内存的,排查错误将会成为一项艰难的任务。

首先给大家介绍一下JVM运行时的数据区。入门的java程序员都接触过一个概念,JVM中存在堆和栈两块数据存储区域。因为栈是一种先进后出的存储结构,所以很适合存储程序运行的逻辑顺序。比如在方法1中调用方法2,此时栈顶元素是方法2,栈底元素是方法1。所以程序运行的时候先运行方法2,然后方法2出栈,再运行方法1,方法1出栈。这就是栈的用法。堆是一个很大的区域。在堆中存储的是程序运行的各种数据,包括对象的实例,常量等等。这是一种粗粒度的划分,但是很好理解。

52e062bb538606816156c28178751a1a.png

如图,这是《Java虚拟机规范(Java SE7 版)》的规定。方法区和堆就是上述堆的概念,方法区是堆的一个逻辑分区,有个别称叫非堆(Non-Heap)。目的是与真正的堆区分出来。

方法区中存放的是虚拟机加载的类信息,常量,静态变量等。

堆的唯一目的是存放对象实例。 堆是垃圾收集管理的主要区域,也称为GC堆。

官方的虚拟机是Hotspot,采用分代收集算法进行垃圾收集(下文有描述)。所以堆可以再进行细分为:新生代和老年代。再将新生代细分一点有:Eden空间、From Survivor空间、To Survivor空间。这两个区域是所有线程共享的。

在“栈区”主要存在三个数据区:虚拟机栈、本地方法栈、程序计数器。

程序计数器是一个很小很小的空间。可以看成当前线程程序执行字节码的行号指示器。此区域是java虚拟机规范中唯一没有规定任何OutOfMemoryError情况的区域。

虚拟机栈和本地方法栈的作用很相似。用于存储局部变量、操作数栈、动态链接、方法出口等。他们两个的区别是虚拟机栈是为执行java方法服务,本地栈是为Native方法( 简单地讲,一个Native Method就是一个java调用非java代码的接口)服务。

232953ccd5e2546dfe469bc0f36b8c3c.png

有了上面的基本概念。下面谈谈java垃圾收集。在java“栈”中时刻进行着进栈和出栈,栈随线程而生,随线程而灭,内存自然回收了。所以GC主要发生在“堆”中。

在堆中占空间最大的就是对象实例了。所以解决回收问题的第一步就是判断对象是否已死。主要有两种算法。

第一:引用计数算法。给对象一个应用计数,引用一次“+1”,失效时“-1”。当引用为0时进行回收。但是这样无法解决相互应用的问题。主流的虚拟机没有采用这种方式。

第二种:可达性分析算法。如下图,通过GC Root可以遍历到的Object节点即为可达,剩下的节点将会被回收。(虽然object6和object7存在引用,但是也会被回收)

859f2b18aba7a43fd4f22425dafa6fca.png

找到了死掉的对象,下一步就是回收了。回收算法这里介绍四种:标记-清除算法、复制算法、标记-整理算法、分代收集算法。

标记-清除:如图将已死对象(灰色)进行标记,回收直接将内存回收掉,这是一种最基本的算法。后续的其他算法都是根据这种思路来的。这种方式明显存在不足。1、效率问题,标记和清除的效率都不高。2、清除后内存空间很零散。如果出现“大对象”则不容易找到一个合适的位置存储。

9042b7551076695328580c3b9fdab662.png

复制算法:将内存空间划分为两个相等的区域,当一个区域空间用完之后将存活的对象复制到另外一个区域,然后回收整个区域。这个算法的优点是高效,缺点是总是有一半的空间被浪费掉。

559b4ab03bb483f18ac1b5581c05fb4c.png

标记-整理法:和标记-清除相似,只是将存活对象向一端进行移动。

49d2a2acbce59549d7ceccf4d0cda717.png

分代收集算法:这其实只是对前面几种算法的综合应用。了解这种算法首先得更进一步了解java堆。上面提到java堆新生代细分为:Eden空间、From Survivor空间、To Survivor空间。他们之间的内存大小为:8:1:1。这其实是为了更好的适应复制算法。IBM研究表明:新生代中的对象98%都是“朝生夕死”的。即运行一次复制算法得到的存活对象是很少的,所以复制算法并不需要采用1:1的空间,而是将一块大的空间分给伊甸园(Eden)两块小的区域分配给两个幸存区(Survivor)。在新生代采用复制算法,每次保留一块幸存区,将另外的一块幸存区和伊甸园中的存活对象复制到保留的幸存区中。这样每次都只有10%的空间被浪费,改善了算法。但是万一伊甸园中和一块幸存区中的对象存活的数量超过了另一块幸存区的容量怎么办?(虽然极少出现这种情况)这时就要依赖老年代做担保了。老年代的对象存活率较高,而且还要为新生代做担保,所以不宜采用复制算法。一般采用标记-清理或者标记整理算法。

6c74746c155670b7f3407d6e72a5b070.gif

对于垃圾回收和内存管理就先说到这里了,欢迎大家在评论区注水交流!

点击链接,阅读更多文章!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值