java方法区、栈和堆(转载)

转载自:https://blog.csdn.net/u013241673/article/details/78574770

Java方法区、栈及堆
一 方法区(Method Area)
1. 什么是方法区(Method Area)?
  《深入理解JVM》书中对方法区(Method Area)描述如下:

  方法区(Method Area)与Java堆一样,是各个线程共享的内存区域。

2.方法区(Method Area)存储什么?
  《深入理解JVM》书中对方法区(Method Area)存储内容描述如下:

  它存储已被Java虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等

2.1 方法区(Method Area)存储的类信息
对每个加载的类型(类class、接口interface、枚举enum、注解annotation),JVM必须在方法区中存储以下类型信息:

  • 这个类型的完整有效名称(全名=包名.类名)
  • 这个类型直接父类的完整有效名称( java.lang.Object除外,其他类型若没有声明父类,默认父类是Object)
  • 这个类型的修饰符(public、abstract、final的某个子集)
  • 这个类型直接接口的一个有序列表

除此之外方法区(Method Area)还存储类信息还有

  • 类型的常量池( constant pool)
  • 域(Field)信息
  • 方法(Method)信息
  • 除了常量外的所有静态(static)变量

方法区(Method Area)存储类信息请参考:参考博客

2.2 方法区(Method Area)存储的常量

  • static final修饰的成员变量都存储于 方法区(Method Area)中


2.3 方法区(Method Area)存储的静态变量

  • 静态变量又称为类变量,类中被static修饰的成员变量都是静态变量(类变量)
  • 静态变量之所以又称为类变量,是因为静态变量和类关联在一起,随着类的加载而存在于方法区(而不是堆中)
  • 八种基本数据类型(byte、short、int、long、float、double、char、boolean)的静态变量会在方法区开辟空间,并将对应的值存储在方法方法区,对于引用类型的静态变量如果未用new关键字为引用类型的静态变量分配对象(如:static Object obj;)那么对象的引用obj会存储在方法区中,并为其指定默认值null;若,对于引用类型的静态变量如果用new关键字为引用类型的静态变量分配对象(如:static Person person = new Person();),那么对象的引用person 会存储在方法区中,并且该对象在堆中的地址也会存储在方法区中(注意此时静态变量只存储了对象的堆地址,而对象本身仍在堆内存中);这个过程还涉及到静态变量初始化问题,可以参考博客:静态变量初始化相关

2.4 方法区(Method Area)存储的方法(Method)

  • 程序运行时会加载类编译生成的字节码,这个过程中静态变量(类变量)和静态方法及普通方法对应的字节码加载到方法区。
  • 但是!!!方法区中没有实例变量,这是因为,类加载先于对应类对象的产生,而实例变量是和对象关联在一起的,没有对象就不存在实例变量,类加载时没有对象,所以方法区中没有实例变量
  • 静态变量(类变量)和静态方法及普通方法在方法区(Method Area)存储方式是有区别的

二 栈(Stack)
栈(Stack):线程私有的内存区域

每个方法(Method)执行时,都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口信息等

栈中所存储的变量和引用都是局部的(即:定义在方法体中的变量或者引用),局部变量和引用都在栈中(包括final的局部变量)

八种基本数据类型(byte、short、int、long、float、double、char、boolean)的局部变量(定义在方法体中的基本数据类型的变量)在栈中存储的是它们对应的值

栈中还存储局部的对象的引用(定义在方法体中的引用类型的变量),对象的引用并不是对象本身,而是对象在堆中的地址,换句话说,局部的对象的引用所指对象在堆中的地址在存储在了栈中。当然,如果对象的引用没有指向具体的对象,对象的引用则是null

三 Java堆(Java Heap)
Java堆(Java Heap) :被所有线程共享的一块内存区域,在虚拟机启动时创建。Java堆(Java Heap)唯一目的就是存放对象实例。所有的对象实例及数组都要在Java堆(Java Heap)上分配内存空间。

由关键字new产生的所有对象都存储于Java堆(Java Heap)

!!! 实例变量(非static修饰的成员变量)和对象关联在一起,所以实例变量也在堆中

java数组也在堆中开辟内存空间

四 示例

public class PersonDemo
{
public static void main(String[] args)
{ //局部变量p和形参args都在main方法的栈帧中
//new Person()对象在堆中分配空间
Person p = new Person();
//sum在栈中,new int[10]在堆中分配空间
int[] sum = new int[10];
}
}


class Person
{ //实例变量name和age在堆(Heap)中分配空间
private String name;
private int age;
//类变量(引用类型)name1和"cn"都在方法区(Method Area)
private static String name1 = "cn";
//类变量(引用类型)name2在方法区(Method Area)
//new String("cn")对象在堆(Heap)中分配空间
private static String name2 = new String("cn");
//num在堆中,new int[10]也在堆中
private int[] num = new int[10];


Person(String name,int age)
{
//this及形参name、age在构造方法被调用时
//会在构造方法的栈帧中开辟空间
this.name = name;
this.age = age;
}

//setName()方法在方法区中
public void setName(String name)
{
this.name = name;
}

//speak()方法在方法区中
public void speak()
{
System.out.println(this.name+"..."+this.age);
}

//showCountry()方法在方法区中
public static void showCountry()
{
System.out.println("country="+country);
}
}
---------------------
作者:zhiman
来源:CSDN
原文:https://blog.csdn.net/u013241673/article/details/78574770
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自www.cnblogs.com/tyj75257/p/9852714.html