标签:
一、Java内存分配
1. Java有几种存储区域?
寄存器
--在CPU内部,开发人员不能通过代码来控制寄存器的分配,有编译器来管理。
堆
--在windows下,栈是向底地址扩展的数据结构,是一块连续的内存的区域,即栈顶的地址和栈的最大容量是系统预先定好的。
--优点:由系统自动分配,速度较快。
--缺点:不够灵活,程序员无法控制。
--存放基本数据类型、开发过程中就创建的对象(而不是运行过程中)。
栈
--是向高地址扩展的数据结构,是不连续的内存区域。
--在堆中,没有堆栈指针,为此也就无法直接从处理器那边获得支持。
--堆的好处是有很大的灵活性。如Java编译器不需要知道从堆里需要分配多少存储区域,也不必知道存储的数据在堆里会存活多长时间。
静态存储区域与常量存储区域
--静态存储区用来存放static类型的变量
--常量存储区用来存放常量类型(final)类型的值,一般在只读存储器中。
非RAM存储
--如流对象,是要发送到另一台机器上。
--持久化的对象,存放在磁盘上。
2. Java内存分配
--基础数据类型直接在栈空间分配。
--方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收。
--引用数据类型,需要用new来创建,既在栈空间分配一个地址空间,又在堆空间分配对象的类变量。
--方法的引用参数,在栈空间分配一个地址空间,并指向堆空间的对象区,当方法调用完后从栈空间回收。
--局部变量new出来时,在栈空间和堆空间中分配空间,当局部变量生命周期结束后,栈空间立即被回收,堆空间区域等待GC回收。
--方法调用时传入的literal参数,先在栈空间分配,在方法调用完成后从栈空间释放。
--字符串常量在DATA区域分配,this在对空间分配
--数组既在栈空间分配数组名称,又在堆空间分配数组实际的大小
3. Java内存模型
Java虚拟机将其管辖的内存大致分三个逻辑部分:方法区、java栈、java堆。
--方法区是静态分配的,编译器将变量绑定在某个存储位置上,而且这些绑定不会再运行时改变。
常数池,源代码中的命名常量、string常量和static变量保存在方法区。
--Java Stack是一个逻辑概念,特点是后进先出。一个栈的空间可能是连续的,也可能是不连续的。
最典型的stack应用是方法的调用,java虚拟机每调用一次方法就创建一个方法帧(frame),退出时则对应的方法帧被弹出。栈中存储的数据也是运行时确定的。
--Java堆分配 意味着以随意的顺序,在运行时进行存储空间分配和收回的内存管理模型。
堆中存储的数据常常是大小、数量和生命期在编译时无法确定的。java对象的内存总是在heao中分配。
二、Java垃圾回收(GC)
1. JVM运行环境中垃圾对象的定义
一个对象创建后被放置在JVM的堆内存中,当永远不再引用这个对象时,它将被JVM在堆内存中回收。或当对象在JVM运行空间中无法通过根集合(root set)到达时,这个对象就被称为垃圾对象。
2. 堆内存
在JVM启动时被创建;堆内存中所存储的对象可以被JVM自动回收,不能通过其他外部手段回收。
堆内存可分为两个区域:新对象区和老对象区
--新对象区可分为三个小区:Eden区、From区、To区
3. JVM中对象的生命周期
创建阶段
--为对象分配存储空间
--开始构造对象
--递归调用其超类的构造方法
--进行对象实例初始化与变量初始化
--执行构造方法体
应用阶段
--特征:系统至少维护着对象的一个强引用;所有对该对象引用强引用(除非显示声明为其他引用)
不可视阶段
--如果一个对象已使用完,并且在其可视区域不再使用,应该主动将其设置为null,即obj=null;这样可以帮助JVM及时发现这个垃圾对象,并且可以及时地回收该对象所占用的系统资源。
4. Java中的析构方法finalize
finalize()方法常称之为终止器
protected void finalize(){
// finalization code here
}
对象即将被销毁时,有时需要做一些善后工作,可以把这些操作写在finalize()方法里。
Java终止器却是在对象被销毁时调用。一旦垃圾收集器准备好释放无用对象占用的存储空间,它首先调用那些对象的finalize()方法,然后才真正回收对象的内存。而被丢弃的对象何时被销毁,应用是无法获知的。大多数场合,被丢弃对象在应用终止或仍未销毁。到程序结束的时候,并非所有收尾模块都会得到调用。
5. 应用能干预垃圾回收吗?
在应用代码里控制JVM的垃圾回收运转是不可能的事。
对垃圾回收有两个途径。第一个就是将指向某对象的所有引用变量全部移走。这就相当于向JVM发了一个消息:这个对象不要了。第二个是调用库方法System.gc()。第一个是一个告知,而调用System.gc()也仅仅是一个请求。JVM接收这个消息后,并不是立即做垃圾回收,而只是对几个垃圾回收算法做了加权,使垃圾回收操作容易发生,或提早发生,或回收较多而已。
希望JVM及时回收垃圾,是一种需求。其实,还有相反的一种需要:在某段时间内最好不要回收垃圾。要求运行速度最快的实时系统,特别是嵌入式系统,往往希望如此。
Java的垃圾回收机制是为所有java应用进程服务的。因此,任何一个进程都不能命令垃圾回收机制做什么、怎么做、做多少。
6. 垃圾回收算法
*引用计数
该算法在java虚拟机没被使用过,主要是循环引用问题,因为计数并不记录谁指向他,无法发现这些交互自引用对象。
--怎么计数?
当引用连接到对象时,对象计数加1
当引用离开作用域或被置为null时减1
--怎么回收?
遍历对象列表,计数为0就释放
--有什么问题?
循环引用问题
*标记算法
标记算法的思想是从堆栈和静态存储区的对象开始,遍历所有引用,标记活的对象。
对于标记后有两种处理方式:
(1)停止-复制
--所谓停止,就是停止在运行的程序,进行垃圾回收
--所谓复制,就是将活的对象复制到另一个堆上,以使内存更紧凑
--优点在于,当大块内存释放时,有利于整个内存的重新分配
--有什么问题?
->停止,干扰程序的正常运行
->复制,明显耗费大量时间
->如果程序比较稳定,垃圾比较少,那么每次重新复制量是非常大的,非常不合算
(2)标记-清除
--也就是将标记为非活的对象释放,也必须暂停程序运行
--优点就是在程序比较稳定,垃圾比较少的时候,速度比较快
--有什么问题?
很显然停止程序运行是一个问题,只清楚也会造成很多内存碎片
--为什么这两个算法都要暂停程序运行?
如果不暂停,刚才的标记会被运行的程序弄乱
Java内存结构
标签:
原文地址:http://www.cnblogs.com/troy-sxj/p/4351748.html