JVM内存分配和回收
本文内容来自《Java编程思想(第四版)》第二章《一切都是对象》和第五章《初始化与清理》。作为一个使用了好几年的Javaer,再次看编程思想的前面章节(不要问我为什么用再,尽管我第一遍看的啥,一点都不记得了。)
-----------------正文分割线---------------------
一个程序需要在计算机中运行,其本质是CPU操作内存中[1]的数据,进行某些运算的过程。所以这个问题是,计算机是如何操作这些数据的。
要解答这个问题,必须知道1.这些数据指的是什么?2.这些数据是如何存储在内存中的?
- 这些数据指的是程序在算出期望结果过程中,所需要的一些信息,包括数据本身(可能是文本,图像等,但这些都是毫无例外的用二进制形式存储的),以及计算过程中产生的中间值,包括一些内存地址,空白的信息(占坑用)等,总之他们都是有结构的被存储在内存中的二进制。[2]
- 这是个大问题,要分步来解答。
a) 数据可以存在哪里?
l 寄存器。存在这里的读取和写入速度都是最快的,因为寄存器是CPU的一部分,而CPU是干活的全部力量,所以CPU和寄存器的交互速度非常快,比内存快上百来倍(未考证)。至于为什么寄存器更快呢?因为寄存器用的是SRAM,而内存是DRAM,SRAM贵多了。至于为什么SRAM比DRAM快,这个我也不知道(喂,在这么下去,要跑题了)。
l 堆栈:堆栈是存在内存的。用的是栈的数据结构,它快的原因是栈的空间分配速度很快,只需要将指针上移下移就行了。(这种上下其手的事情慢了怎么行。)
l 堆:堆也是放在内存的,而且只比堆栈少一个字!不过它的速度慢多了,这是因为它是堆的数据结构,堆天生就比栈慢。但是堆栈太大了效率就吃不消,你去试试对乐山大佛·上上下下啊!而堆就不一样了,能存的东西就多多了。
l 其他:包括常量堆,流、持久化对象(这个是存在磁盘和网络上的)。
b) 然后呢?(如何操作存在内存的数据)
对内存中数据的操作,汇编是直接操作的,因此你可以在组成原理中看到,内存寻址是一块很重要的内容。C/C++是采用“指针”来间接操作的,它要负责内存的分配和回收,例如malloc就是要内存的节奏。
在Java中,一切都是对象。对象有可能很庞大也可能很小。Java将对象的引用存储在栈上,这样可以快速找到定位,将实际的对象存储在堆中。引用的本质是内存地址,它直接指向堆里相应的对象。所以你在Java中输出this的时候,其实输出的是Java对象的内存地址。
前面说了,堆的操作比较慢。但是实际上,Java的堆并不慢,根据编程之美的说法,Java堆的效率可以媲美某些语言(我也不知道某些是哪些)的栈。这主要得益于JVM良好的垃圾回收机制。
c) JVM垃圾回收机制
程序在运行过程中,需要不断的申请新的内存空间,然后释放掉不用的对象。程序删除不用的内容后,原来这些内容占着的坑(内存空间)就会空出来。如此便会造成大量的内存碎片存在。内存碎片会降低内存使用率,并导致一些大内存对象的分配显得困难。整合这些内存碎片,是非常消耗资源的行为(但是又不得不整合)。JVM的内存回收机制(垃圾回收机制)干的就是这个活。
那么,JVM是如何进行垃圾回收的呢?
简言之,就是根据某些策略,找到那些不用的对象,并将它们释放掉。当然如果能顺便解决内存碎片就更好了,么么哒。
d) 如何找到失活对象?(根据什么策略呢)
有个理论上非常简单的方式就是,如果一个对象被引用了,那么给它的计数增加1,对象被释放掉了,就减去1,那么当一个对象的引用是0的时候,他就毫不留情的被垃圾回收机制回收了。这个方式叫做“引用计数”。但是这个方式有个致命的问题:当两个对象相互引用的时候,计数就永远不为0,即便这些对象是需要被释放掉的。
所以,JVM就不用这个方式啦。
JVM的做法是:遍历栈里的所有引用,有引用的对象便是活的对象,没引用的对象,就是被当做孤魂野鬼来处理。为了解决内存碎片的问题,JVM使用了一种叫做“停止-复制(stop-and-copy)”的做法,即暂停当前程序,然后将活的对象复制到另一片内存区域;如此,既解决了内存碎片(新复制的对象在内存上是连续的),有解决了垃圾回收(没有引用的对象就被抛弃了)。但是这样子,效率上并不太高,另外,还需要一大片内存来做备胎。另外,程序稳定运行后,内存碎片可能并不多。
这时候,JVM的另一个套机制,叫做标记-清扫(mark-and-sweep)的方式。这种方式也是从栈出发,遍历所有引用,为有引用的对象标记存活标记;标记之后,再开始清扫,即清理没被标记的对象。这时候得到的结果,其内存是不连续的。
JVM会监视内存使用状态,在程序稳定的时候,启动标记-清扫方式,当堆碎片过多的时候,启动停止-复制方式。JVM管这个过程叫做自适应的垃圾回收机制。
在上面所述的过程中,内存是以块为单位进行分配的。较大的对象会占据一整个块。每个块都有一个参数叫做代数(generation count),标记其是否存活。对于大型对象,在停止-复制过程中,也不会被再复制一遍,只是代数增加。(这个是为了减少复制的内容,从而减少内存占用。)
JVM内存分配和回收的更多相关文章
- 最简单例子图解JVM内存分配和回收
一.简介 JVM采用分代垃圾回收.在JVM的内存空间中把堆空间分为年老代和年轻代.将大量(据说是90%以上)创建了没多久就会消亡的对象存储在年轻代,而年老代中存放生命周期长久的实例对象.年轻代中又被分 ...
- 最简单例子图解JVM内存分配和回收(转)
本文转自http://ifeve.com/a-simple-example-demo-jvm-allocation-and-gc/ http://www.idouba.net/a-simple-exa ...
- JVM内存分配与回收
1.内存分配与回收策略 内存自动管理:自动化的解决了对象内存分配和回收对象内存的问题. 一般在堆上分配对象,也可能经过JTI编译后间接在栈上分配. 主要分配在新生代的Eden区,如果启动了本地线程分配 ...
- 窥探JVM内存分配和回收的过程
一.环境 JDK 垃圾收集器 是否启用TLAB 通用JVM参数(堆内存分配见下图) 1.6.0_65 Serial + Serial Old 否 -Xms20m -Xmx20m -Xmn10m -XX ...
- jvm内存分配和回收策略
在上一篇中,已经介绍了内存结构是什么样的. 这篇来介绍一下 内存是怎么分配的,和怎么回收的.(基本取自<深入理解Java虚拟机>一书) java技术体系中所提倡的自动内存管理最终可以归结为 ...
- 图解JVM内存分配和回收
一.简介 JVM采用分代垃圾回收.在JVM的内存空间中把堆空间分为年老代和年轻代.将大量(据说是90%以上)创建了没多久就会消亡的对象存储在年轻代,而年老代中存放生命周期长久的实例对象.年轻代中又被分 ...
- JVM 内存分配和回收策略
对象的内存分配,主要是在java堆上分配(有可能经过JIT编译后被拆为标量类型并间接地在栈上分配),如果启动了本地线程分配缓冲,将按线程优先在TLAB上分配.少数情况下也是直接分配到老年代,分配规则不 ...
- A4. JVM 内存分配及回收策略
[概述] Java 技术体系中所提倡的自动内存管理最终可以归结为自动化地解决两个问题:给对象分配内存以及回收分配给对象的内存. 对象的内存分配,往大方向讲,就是在堆上分配,对象主要分配在新生代的 Ed ...
- JVM——内存分配与回收策略
1.对象优先在Eden区分配 大多数情况下,对象在新生代Eden区分配.当Eden区没有足够的空间进行分配时,虚拟机将发起一次Minor GC. 虚拟机提供了 -XX:+PrintGCDetails这 ...
随机推荐
- 协同办公平台Worktile体验分享(转)
自从组建团队以来,做的每一个项目.每一次活动,电脑里就会存放了N个不同名称的相同文档, 工作内容.资源文档非常零散,严重影响了工作效率. 之前用Dropbox共享文档,结果被墙了.用印象笔记,结果一个 ...
- Android Studio 如何导入第三方jar 包
第一步: 将第三方jar包加入到libs文件夹中 第二步: 分为两种情况 第一种是打开工程所在Project Structure,然后选择Dependencies,点击那个加号选择File Depen ...
- NFC介绍
简介 本文介绍Nokia设备所支持的近场通信技术(NFC)及相关的功能.旨在为使用 Qt/Symbian/Java™ API为Nokia手机开发应用的开发者 刚开始接触NFC开发时提供有用的信息. 什 ...
- 原生应用native、Web应用、混合应用hybrid:3者的优缺点解析
最近原生应用.Web应用.混合应用的名字让我们听得比较熟悉了,现在我们就通过评析各种应用的优缺点来更进一步看看这三者的区别. 一. 原生应用: 你使用过微软PowerPoint 或者 Word吧?这些 ...
- python编辑器对比和推荐
python编辑器对比和推荐 我先给一个初步的表格吧,大家如果有什么意见,或有补充,欢迎提出.有些我没有用过,先不写了.以下是我使用过的python IDE: 除了PythonWin, Visua ...
- IVM import vector machine
本文为<Kernel Logistic Regression and the Import Vector Machine>的阅读笔记是技法课的课外阅读 Abstract:基于KLR ker ...
- hunnu11543:小明的烦恼——分糖果
Problem description 小明在班里一直是个非常公正的孩子.这点同学和老师都非常清楚,这不,老师每周都会从家里带来一些糖果.然后叫小明把糖果分给其它小朋友,但这个班里的同学都有一个非 ...
- 【简单项目框架一】Fragment实现的底部导航
流行的应用的导航一般分为两种,一种是底部导航,一种是侧边栏. 我所做的项目涉及到比较多的是底部导航,今天我就把项目中使用的一种实现方式分享一下. 主要实现思路是:在一个Activity里面底部添加四个 ...
- Chrome浏览器切换到之前打开的标签页会重新加载
这是谷歌的一种策略.当系统内存不足时,系统会自动从内存中舍弃标签页 在地址栏输入chrome://flags/#automatic-tab-discarding,设置为停用即可.
- 根据树父子ID拼接无限极树结构表的名称
declare @c varchar(50)set @c='572a3d51-ef7a-459e-a5cd-ebf0fca51e8b' --能查出来呀 你试试,我试一下,好像可以啦谢谢 declare ...