虚拟机规范中将内存分为六大部分,分别为PC寄存器、JAVA虚拟机栈、JAVA堆、方法区、运行时常量及本地方法栈。
1.PC寄存器:线程独占
;
2.JAVA虚拟机栈:线程独有
;JAVA虚拟机栈是在创建线程的同时创建的,用于存储栈帧,JAVA虚拟机栈也是线程独有的。
3.JAVA堆:全局共享
;
4.方法区:全局共享
;它主要存储的是
运行时常量池
字段信息
方法信息
构造方法
普通函数
的字节码内容以及一些特殊方法。线程独有
,本地方法栈是一个传统的栈,它用来支持native方法的执行。如果JAVA虚拟机是使用的其它语言实现指令集解释器的时候,也会用到本地方法栈。1.一部分是全局共享:
内存作为一种有限的资源,然而随着时间的推移内存的垃圾会越来越多。但java并没有提供类似于C/C++这一类内存释放和管理的机制,而是通过内置的GC进行内存的管理。GC的主要工作是:
1.哪些对象可以被回收?
2.何时回收?
3.采用什么样的方式回收?
有一种比较简单直观的办法,它的效率较高,被称作引用计数算法
。但是这个算法有一个致命的缺陷,那就是对于循环引用的对象无法进行回收。
解决哪些对象可以被回收的问题
)由于引用计数算法的缺陷,所以JVM一般会采用一种新的算法,叫做根搜索算法
。它的处理方式就是,设立若干种根对象
,当任何一个根对象到某一个对象均不可达时
,则认为这个对象是可以被回收
的。
GC roots(GC根
),在JAVA语言中,可以当做GC roots的对象有以下几种:
垃圾搜集的算法主要有三种,分别是标记-清除算法
、复制算法
、标记-整理算法
。这三种算法都扩充了根搜索算法。
当堆中的有效内存空间(available memory)被耗尽的时候,就会停止整个程序(也被成为stop the world),然后进行两项工作,第一项则是标记
,第二项则是清除
。
通俗地说也就是当可用内存即将耗尽时,逐步完成以下工作:
缺陷:
复制算法由“标记-清除算法
”基础上演化而来。
复制算法将内存划分为两个区间,在任意一个时间点,所有动态分配的对象只能分配在其中一个区间(活动区间),而另一个区间(空闲区间)则是空闲的。
当可用内存即将耗尽时,会逐步完成以下工作:
复制算法
弥补了标记-清除算法
中内存布局混乱的缺点,但其缺点也很明显:
复制这一工作所花费的时间,在对象存活率达到一定程度时,将会变的不可忽视。
复制算法要想使用,最起码对象的存活率要非常低才行,而且最重要的是,我们必须要克服50%内存的浪费。
标记-整理算法
和标记-清除算法
类似,可以分成两个阶段:标记和整理
优点:标记/整理算法不仅可以弥补标记/清除算法当中,内存区域分散的缺点,也消除了复制算法当中,内存减半的高额代价
缺点:标记/整理算法唯一的缺点就是效率也不高
复制算法、标记/整理算法、标记/清除算法共同点:
区别:
没有最好的算法,只有最合适的算法,不同算法适合不同的场景。
适合使用复制算法
采用标记/整理
或者标记/清除算法