黑马程序员——Java内存结构

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

一、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)标记-清除
     --也就是将标记为非活的对象释放,也必须暂停程序运行
     --优点就是在程序比较稳定,垃圾比较少的时候,速度比较快
     --有什么问题?
          很显然停止程序运行是一个问题,只清楚也会造成很多内存碎片
     --为什么这两个算法都要暂停程序运行?
          如果不暂停,刚才的标记会被运行的程序弄乱
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值