转载

深入理解java虚拟机(1)------内存区域与内存溢出

在C++领域,关于C++的内存存储,结构等等,有一本书:深度探索C++对象模型,讲解的非常透彻。

而Java确把这一工作交给了虚拟机来处理。

我们首先来看看关于内存的问题。

1.问题:

1)java 的局部变量存在那里,类型怎么存放的?

2)static 变量

3)final 变量

4)method是存放的那里的

5)class类 & 内部类 是如何存放

2.java虚拟机运行是数据区

2.1程序计数器

线程隔离数据,记录当前线程执行的位置。

PC计数器

由于Java虚拟机的多线程,是由线程轮换的方式分配CPU的。所以线程切换后,需要恢复到原来执行的地方

没有线程都需要一块内存来记录这个执行位置,此内存是线程私有的。

2.2Java虚拟机栈

这个栈就是我们常见的java 面试题中一般会问 heap & stack 的区别。 这里的stack就是我们说的虚拟机栈。

这个栈是存放每个method执行的时候的局部变量表,动态连接,方法出口等信息。

局部变量表存放:局部变量类型,已经基本类型的变量。

栈中可以理解为存放对象的引用,为对象本身存放在堆。

如果申请的内存不够,就会OOM。

2.3本地方法栈

这个东西同Java虚拟机栈非常类似,这里存放这native方法的一些信息。

2.4Java堆

千呼万唤始出来,对象实例就是存放在这个地方。也是java内存最大的地方。

GC的主要工作就是释放这里不用的内存。

这块区域为所有线程共享。所以android就会有activity或者service在非前台状态下,是否低优先级的情况。

2.5方法区

这块地方存放的就是已经加载的类信息,静态变量,常量等。

String abc = “abc”; 这后面的“abc”就存放在这里。

2.5.2 运行时常量区

java在非编译阶段,也可以是一种常量的形式,比如:

String str = "abc"+"d";

它会生成“abcd”常量在运行时候。

3.HotStot虚拟机对象探秘

java对象的创建过程分成2步:

1)加载类信息,存放在方法区

2)根据类信息,分配内存存放对象,内存在堆区。

分配内存的常见方式:

1)假设内存在堆区分为2块,一块是已经在使用的,一块是还没有分配的,这样我只要设置一个指针,来区分这两块区域。

当分配新的内存时,移动指针即可。

2)内存区域是不连续的,这样我只能在空闲的内存中,找到一块足够大的内存来分配,这种为空闲列表的方式。

但是,当分配内存时,会有同步的问题。

要么保证分配操作是原子操作,或者就是给每个线程优先分配一小块内存(Thread Local Allocation Buffer)

这个东西在android looper机制的时候,有所体现。

接下来就是对对象进行设置:

对象是那个类的实例,如何才找到对象的元数据信息,对象的hash表,对象的GC分布年龄等。

从程序员的角度看,一个对象在内存中已经创建,但是init的方法还没有执行。对象还没有按照程序员的意愿进行初始化。

3.1 对象的内存布局

在HotStot中,对象的布局可以分为3块:对象头,实例数据,和对其填充。

对象头根据虚拟机的位数,32bit或者64bit。

这部分被以极限的算法,来存储不少的信息。

实例数据部分,存的是真正有效的信息,这部分会存父类的信息和子类的信息。

3.2对象的访问方式

reference 指向的是另一个类的对象,所以它指向的实际是堆中的另一块内存而已。

深入理解java虚拟机(1)------内存区域与内存溢出

HotSopt使用的是第二种方式。

正文到此结束
Loading...