您的位置:首页 > 编程语言 > Java开发

Java对象创建过程和内存结构分析

2015-05-03 16:02 761 查看
JAVA内存分配和管理是JAVA的核心技术之一,在看了尚硅谷宋红康老师讲解的JAVA内存知识之后,结合《深入理解JVM这本书》对自己所学的知识进行简单的总结,写了这篇日志。

1.JAVA内存分区

根据存储数据的不同,java内存通常被划分为5个区域:程序计数器(Program Count Register)、本地方法栈(Native Stack)、方法区(Methon Area)、栈(Stack)、堆(Heap)。

程序计数器(Program
Count Register):又叫程序寄存器。JVM支持多个线程同时运行,当每一个新线程被创建时,它都将得到它自己的PC寄存器(程序计数器)。如果线程正在执行的是一个Java方法(非native),那么PC寄存器的值将总是指向下一条将被执行的指令,如果方法是
native的,程序计数器寄存器的值不会被定义。 JVM的程序计数器寄存器的宽度足够保证可以持有一个返回地址或者native的指针。

栈(Stack):又叫堆栈。JVM为每个新创建的线程都分配一个栈。也就是说,对于一个Java程序来说,它的运行就是通过对栈的操作来完成的。栈以帧为单位保存线程的状态。JVM对栈只进行两种操作:以帧为单位的压栈和出栈操作。我们知道,某个线程正在执行的方法称为此线程的当前方法。我们可能不知道,当前方法使用的帧称为当前帧。当线程激活一个Java方法,JVM就会在线程的
Java堆栈里新压入一个帧,这个帧自然成为了当前帧。在此方法执行期间,这个帧将用来保存参数、局部变量、中间计算过程和其他数据。从Java的这种分配机制来看,堆栈又可以这样理解:栈(Stack)是操作系统在建立某个进程时或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域,该区域具有先进后出的特性。

堆(Heap):Java堆(Java
Heap)是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域。在此区域的唯一目的就是存放对象实例,几乎所有的对象实例都是在这里分配内存,但是这个对象的引用却是在栈(Stack)中分配。因此,执行String s = new String("s")时,需要从两个地方分配内存:在堆中为String对象分配内存,在栈中为引用(这个堆对象的内存地址,即指针)分配内存,如下图所示。



方法区(Method
Area):当虚拟机装载一个class文件时,它会从这个class文件包含的二进制数据中解析类型信息,然后把这些类型信息(包括类信息、常量、静态变量等)放到方法区中,该内存区域被所有线程共享,如下图所示。本地方法区存在一块特殊的内存区域,叫常量池(Constant Pool),这块内存将与String类型的分析密切相关。



2.JAVA对象创建过程分析

以创建Person对象为例,分析对象创建过程中在内存中的分配情况以及方法的调用过程。

class Person
{
private String name;
private int age;

DemoTest dTest = new DemoTest();
public Person(String name, int age)
{
System.out.println("这是person的构造函数");
this.name = name;
this.age = age;
}

{
System.out.println("这是person的构造代码块");
}

static
{
System.out.println("这是person类的静态代码块");
}
public void setName(String name)
{
this.name = name;
}

public void show()
{
System.out.println("name = "+name + "::"+"age = "+age);
}

}

class DemoTest
{
public DemoTest()
{
System.out.println("这是一个测试的类");
}
}

public class test
{
public static void main(String[] args)
{
Person p = new Person("gao",24);
p.setName("wz");
p.show();
}
}

输出结果:这是person类的静态代码块

这是一个测试的类

这是person的构造代码块

这是person的构造函数

name = wz::age = 20

首先栈中的main函数执行Person = new Person("gao",24);这个简单的语句会涉及到如下几个步骤:

1,由于是要创建Person类对象,java虚拟机(JVM)先去找Person.class文件,如果有的话,将其加载到内存。

2,将类型信息(包括静态变量,方法等)加载进方法区。

3,执行该类中static代码块,如果有的话,对Person.class类进行初始化。(此时输出‘这是person类的静态代码块’)

4,到这时才进行堆内存空间的开辟,并为对象分配首地址。

5,在堆内存中建立对象的成员属性,并对其进行初始化(先进行默认初始化再进行显示初始化。(此时输出 ‘这是一个测试的类’)

6,进行构造代码块的初始化,由此看出构造代码库初始化的优先级要高于对象构造函数的初始化。 (此时输出 ‘这是person的构造代码块’)

7,对象的构造函数进行初始化。(此时输出 ‘这是person的构造函数’);

8,将堆内存中的地址赋给栈内存中的p变量。

以上是我的java虚拟机机制的一些理解,由于JVM的复杂性,完全理解它是很困难的,如果文章中有错误的还望大家指出。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: