`
gzcj
  • 浏览: 286619 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论
阅读更多


一个java应用在运行中所创建的所有类实例或数组都放在了同一个堆中,并由应用所有的线程共享。因为一个java应用
唯一对应了一个jvm实例,所以每个应用都独占了一个堆,它不可能对另一个应用的堆进行破坏。然而,一个多线程应用必须考虑同步问题。

jvm有在堆中分配对象的指令,却没有释放对象的指令。正如你无法用java代码去释放一个对象一样,字节码也没有对应的
功能。应用本身不用去考虑何时和用什么方法去回收不用对象所占用的内存。通常,jvm把这个任务交给垃圾收集器。

 

垃圾收集
一个垃圾收集器的主要工作是回收不再被引用的对象所占用的内存。它也可能去移动仍然使用的对象以减少内存碎片。

jvm规范没有指定垃圾收集使用什么技术,这些都由jvm的实现者去定夺。因为对象的引用可能存在很多地方,如java堆栈,堆,方法区,native方法栈。所以垃圾收集技术的使用在很大程度上影响了运行数据区的设计。象方法区一样,堆不必是一块连续的内存区,也可以根据应用的需要动态调整大小。可以把方法区放在堆的顶部,换句话说就是类型信息和实际
对象都在同一个堆上。负责清理对象的垃圾收集器可能也要负责类的回收。堆的初始化大小,最大最小尺寸可以由用户或程序指定。

 

对象表现( Object Representation)
(译者:C++中称为对象模型)jvm规范没有规定对象在堆中该如何表现。对象的表现会影响堆和垃圾收集的整个设计,它由jvm的实现者决定。对象的主要数据是由对应类和其父类声明的实例变量组成(instance variables 译者:对应Class variables, Class variables存储在方法区中,这在上篇译文中有讲)jvm应该既能够从一个对象引用快速的找到实例变量,也能够快速的找到存储在方法区中的类数据。所以在对象中常常会有一个指向
方法区的指针。

一个可能的实现是把堆分成两部分:一个句柄池和一个对象池。如图5-5一个对象引用是一个指向句柄池的native指针。句柄池的每个条目有两部分:一个指向对象实例变量的指针,一个指向方法区类型数据的指针。这种设计的好处是利于堆碎片的整理,当移动对象以减少碎片时不用更新每个对象引用而只更改句柄就可以了。缺点是每次访问对象都要经过两次
指针传递。

 

 

另一种设计是使对象指针直接指向对象实例变量,而在对象实例内包含一个指向方法区类型数据的指针。这样的设计的优缺点正好与前面的方法相反。如图5-6.

 

 

jvm有若干理由使它能够从对象引用中得到对应类的数据。
1。 当应用试图转型(cast)时,jvm需要保证要转的类型是此类型本身
    或是这个类型的父类型。
2。 当应用进行 instanceof 操作时
3。 当应用激活一个实例方法时,jvm必须进行动态绑定,而它所依赖的信息
    不是这个引用的类型,而是这个对象对应的类的信息。    不管对象以什么形式表现,好像都有一个能够方便访问的方法表。由于方法表能加速实例方法的调用,所以对jvm的性能有重要的影响。jvm规范并没有规定必须要使用方发表,例如在内存稀少的环境下,可能不能负担方法表的内存支出。
然而如果使用了方法表,它就应该能够快速的从一个对象引用中获得。图5-7显示了一种连结方法表和对象引用的实现。每个对象的数据包含一个指向特殊数据结构的指针,这个数据结构位于方法区,它包括两部分:
     一 一个指向方法区对应类数据的指针
    二 此对象的方法表

方法表的每一项都是一个指向方法数据的指针,方法数据包括:
   一 此方法的操作数堆栈和局部变量区的大小
   二 方法的字节码
   三 异常表
这些信息足够jvm去激活一个方法了。方法表的函数指针包括类或其父类声明的函数。也就是说,方法表所指向的函数可能是此类声明的,也可能是它继承下来的。

 

如果你熟悉c++的内部工作原理,你会发现这和c++的vtbl非常相似。在c++中,对象由实例数据和一组指向虚拟函数的指针组成,jvm也可以采用这种方法。jvm可以在堆中为每个对象都附加一个方法表,这样较之图5-7会占用更多的内存,
但可提高一些效率。这个方案适用在内存足够充裕的系统。(译者:总觉得作者对c++有些误解,c++的对象模型在函数表上的设计和图5-7是类似的,在有虚拟函数的情况下(不考虑多继承),每个对象也只多出一个指向vtable的指针,而vtable也是与类关联的。)

 

除了图5-5和5-6显示的实例数据外,对象数据还有一个逻辑部分,那就是对象锁(object's lock)。在jvm中每个对象都有一个锁,以用于多线程访问时的同步。在某个时刻只有一个线程拥有这个对象锁,而且只有这个线程才可以对对象的数据进行访问。其他要访问这个对象的线程只有等待,直到拥有对象锁的线程释放所有权。当一个线程拥有对象锁后,可以继续对锁追加请求。但请求几次,必须对应释放几次。

许多对象在其生命期内可能不需要加锁,这样也不需要附加数据,正如图5-5 5-6所示,对象数据内没有一个指向锁数据(lock data)的指针。而只有当需要加锁的时候才分配对应锁数据,但这时需要其他的方法来联系对象数据和对应的锁数据,例如把锁数据放在一个以对象地址为索引的树中。除了实现锁需要的数据,每个java对象逻辑上还有为实现同步而添加的数据。
锁是用来实现多个线程对共享数据的互斥访问,而同步则是实现多个线程为完成一个共同目标而协调工作。同步由等待方法和通知方法共同实现。每个类都从Object那里继承了三个等待方法(三个名为wait()过载函数)和两个通知方法(notify()
和notifyAll())。当一个线程在一个对象上调用wait方法,jvm就阻塞了这个线程并把它放在了这个对象的等待集(wait set)中。当有一个线程在这个对象调用了通知方法,jvm就会在将来的某个时间唤醒一个或多个在等待集中阻塞的线程。正像锁数据一样,并不是每个对象都需要同步数据。许多jvm实现都把同步数据与对象数据分开,只有在需要时才为此对象创建同步数据,一般是在第一次调用等待方法或通知方法时。

最后,一个对象还可能要包含与垃圾收集有关的数据。垃圾收集必须要跟踪每个对象,这个任务不可避免的要附加一些数据,数据的类型要视垃圾收集的算法而定。例如,假如垃圾收集使用标志清除算法,必须要一个数据来标志此对象是否被引用。像线程锁一样,这些数据也可以放在对象外。一些垃圾收集技术只在运行时需要额外数据。例如标志清除算法使用一个位图来标志对象的引用情况。除了标志对象的引用情况外,垃圾收集还要区分一个对象是否调用了finalizer。在收集一个对象之前,垃圾收集器必须调用声明了finalizer的类的对象。java语言规范指出垃圾收集器对某个对象只能调用finalizer一次,在finalizer中允许这个对象复生(resurrect),即使之再次被引用。这样当这个对象再次被收集时,就不再调用finalizer了。需要finalizer的对象不多,而复生的对象更少,所以对一个对象回收两次的情况很少见。这样用来标志
finalizer的数据虽然逻辑上是对象的一部分,但通常与对象分开保存。

 

数组表现
再java中,数组是一个成熟的对象。像其他对象一样,数组也存储在堆上,jvm实现的设计者也有权决定数组的表现。

数组也有一个相关的类实例(Class instance),所有具有相同维度和类型的数组同为一个类,而不管数组的长度(多维数组每一维的长度)。
例如一个有三个ints的数组和一个有六个ints的数组都是同一个类。数组的长度只与实例数据有关。数组类的名称由两部分组成,一个是用'['表示的维和一个字符表示的类型。
例如,类型为ints的一维数组的类名为“[I”。类型为bytes的三维数组为“[[[B”。类型为Object的二维数组为“[[Ljava.lang.Object”。多维数组被表示为数组的数组。例如,类型为ints的二维数组,将表示为
一个一维数组,数组元素是一个一维ints数组的引用。如图5-8每个数组必须保存的数据是数组的长度,jvm必须能够从一个数组的引用得到此数组的长度,通过下标访问数组元素,检查数组下标是否越界,激活Object声明的方法。

分享到:
评论

相关推荐

    在eclipse设置JVM heap 的最小值与最大值.bmp

    在eclipse设置JVM heap 的最小值与最大值的图案

    ibm HeapAnalyzer JVM内存分析工具 ha457.jar下载

    ibm HeapAnalyzer JVM内存分析工具 ha457.jar下载

    Java VM Heap 堆分析(节选)

    JVM堆分析,Java VM堆分析(节选)。 JProbe 是目前最好的Java性能优化工具之一,在全球有最多的用户。 本文档不但介绍了JProbe的在解决内存问题方面的功能和使用,同时还介绍了必要的Java内存管理的背景知识,深入...

    JVM GC原理, heapsize调优

    详细介绍JVM gc原理, heapsize调优方法。 本文虽以IBM jdk为例讲解,但实际不仅限于于IBM jdk,其原理和方法同样适用于oracle jdk

    jvm 内存分析文档

    1.jvm内存结构及功能概述 2.Jvm Heap 内存结构 3.Jvm 的内存分配

    JVM入门实战/arthas实战/垃圾回收算法/垃圾回收器/jvm内存模型分析

    1.3 Heap堆内存模型 第三节:定位垃圾对象的依据 1.1 引用计数法 1.2 可达性算法 第四节:垃圾回收算法 1.1标记清除算法 1.2复制算法 1.3 标记整理(标记压缩)算法 第五节:垃圾回收器 1.1Serial/Serial Old...

    JVM内存设置与调优指南

    JVM内存设置与调优指南

    JVM规范--高手总结

    2.5.4 堆(heap)和栈(stack) 20 JAVA垃圾收集器 21 3.1 垃圾收集简史 21 3.2 常见的垃圾收集策略 21 3.2.1 Reference Counting(引用计数) 22 3.2.2 跟踪收集器 22 3.3 JVM的垃圾收集策略 27 3.3.1 Serial Collector ...

    jvm原理及调优

    一、JVM概述 二、JVM的体系结构 三、JVM运行时数据区 3.1 PC寄存器 3.2 JVM栈 3.3 堆(Heap) 3.4 方法区域 3.5 运行时常量池 3.6本地方法堆栈 四、Jvm堆 五、Jvm调优

    jvm调优实战经验

    小池塘A(堆内存):JVM运行时数据区域,它为类实例和数组分配的内存。堆可以是固定大小的也可以是可变大小的。其中 Heap = {Old + NEW = { Eden , from, to } }。 小池塘B(非堆内存):包括所有线程之间共享的一个...

    IBM HeapAnalyzer

    Java dump文件查看工具 IBM heapAnalyzer, IBM HeapAnalyzer是一款免费的JVM内存堆的图形分析工具,它可以有效的列举堆的内存使用状况,帮助分析Java内存泄漏的原因。

    Heap Dump的IBM分析工具.zip

    heap dump: heap dump文件是一个二进制文件,它保存了某一时刻JVM堆中对象使用情况。HeapDump文件是指定时刻的Java堆栈的快照,是一种镜像文件。

    JVM参数设置详细说明

    后来我们就用CMS gc(-XX:+UseConcMarkSweepGC),当时的总heap还是3g,新生代1.5g后,观察不是很理想,改为jvm heap为2g新生代设置-Xmn1g,在这样的情况下young gc发生的频率变成7、8秒一次,平均每次时间40-50毫秒...

    JVM内存段分配,Java垃圾回收调优,Heap设定

    JVM内存段分配,Java垃圾回收调优,Heap设定

    IBM heapdump analyzer

    在一些平台上,在有些情况下,javacore也被称为javadump,它包含jvm和应用程序相关的在特定时刻的一些诊断信息,如操作系统,应用程序环境,线程,native stack本地堆,锁,和内存的信息。在生成heapdump文件的时候...

    java内存溢出原因

    JVM PermGen space 溢出 JVM heap space 溢出 Native Heap 溢出 三种溢出原因 供大家参考

    JVM内存模型

    JVM内存模型,永久区内存( Permanent space )和堆内存(heap space)。

    eclipse.ini

    在JVM中堆之外的内存称为非堆内存(Non-heap memory)”。 可以看出JVM主要管理两种类型的内存:堆和非堆 简单来说:堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给自己用的,所以方法区、JVM...

    01HeapAnalyzer.rar

    IBM heapdump分析工具,分析内存泄漏和JVM内存使用率高的情况,高CPU和频繁垃圾回收分析。

Global site tag (gtag.js) - Google Analytics