Java的内存分配

Jvm中将内存分为:寄存器,栈,堆,方法区(静态域,常量池)

1. 寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制,可以不理会

2. 栈: (stacksegment)

2.1:存取速度仅次于寄存器的存储区,速度快,先进后出(first in last out)

2.2:存放8大基本类型数据(int, short, long, byte, float, double, boolean, char)和对象引用,(仅存放引用,不存放数据)

存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中)

数据可以共享(详见备注例子)

2.3: 存放数据大小确定,生存期必须是确定的,缺乏灵活性

对于每个线程都有一个栈,每个栈中的数据都是私有的,不能访问别的栈中对象

备注例子:

int a = 3;

   int b = 3;

   首先栈中创建变量为a的引用,查找栈中是否有3,有则把a指向该地址,否则就开辟一个地址存放3 (3为基本数据类型,存放在常量池中,a为3的引用存放在栈中);

   那么b的引用就直接指向了a中所指向的地址3;

    如果将 b=3 改为 b=4 并不会影响a的值,会在栈中查找是否有4的地址,有则将b的引用指向4的地址,没有就开辟一个地址存放4

   这里的引用与java中类的引用不同

2.4: 对于String型数据,如果是编译期生成如 String a = "123"; a 在栈中 ,123 在常量池中,

如果是在运行期生成String a = new String("123");a在栈中,123会在常量池中生成(如果常量池中不存在),并在堆内存中生成常量池的"123"的拷贝对象"123";

备注:这里new String("123")生成了两个对象(如果常量池中不存在),否则就是生成一个对象

2.5: 生命周期:由编译器自动分配释放,存放函数的参数值,局部变量的值等,具体方法执行结束之后,系统自动释放JVM内存资源

3.堆: (heapsegment)

优势是:可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。

缺点是:由于要在运行时动态分配内存,存取速度较慢。

new的对象都存在这里

多线程共享该堆

生命周期 : 一般由程序员分配释放,存放由new创建的对象和数组,jvm不定时查看这个对象,如果没有引用指向这个对象就回收,或由GC回收

4.方法区:方法区是系统分配的一个内存逻辑区域,是JVM在装载类文件时,用于存储类型信息的(类的描述信息)。

4.1.常量池:

常量池指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。

除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的常量值(final)还包含一些以文本形式出现的符号引用

比如:

类和接口的全限定名;

字段的名称和描述符;

方法和名称和描述符。

final的具体规则

·final标记的类不能被继承

·final标记的方法不能被子类重写

·final标记的变量(成员变量或局部变量)即成为常量,只能赋值一次

在这里要详细的说下final(举例):

   String s1="我爱LOL"; //s1指向"我爱LOL"

String s2="我爱"+"LOL"; //只是将s2指向了"我爱LOL"

System.out.println(s1==s2); //true

String str1="我爱";

String str2="LOL";

String s3=str1+str2; //str1,str2为变量,不执行宏替换,编译时无法使s3指向常量池,所以会生成新的对象

System.out.println(s1==s3); //false

这里将str1,str2用final修饰,就使的 s1== s3 为true

final修饰的变量实质上就是一个“宏变量”,编译器会把程序中所有用到该变量的地方替换成该变量的值

4.2.静态域:(datasegment)

存放静态成员(static定义的)

生命周期: 存放全局变量,静态变量和字符串常量,不释放

对于jvm内存分析完,我们来将内存合理的用到实际的开发中来: 开发环境的合理化内存分配

在开发环境中内存不如jvm中这么详细,只分为 堆 和 非堆 两个内存区, 因此我们设置的时候就很简单了,设置堆的最大最小值,设置非堆的最大最小值

详解 堆 ,非堆:

堆:指的是运行时的数据区域内存,相当于jvm中的堆,而在jvm中的堆是存new 数据和数组数据的,由此可见这是留给我们开发人员用的

非堆:指的是编译时的数据区,相当于jvm中的方法区,存放静态方法,常量,构造函数,字段等编译后的代码,由此可见这是留给jvm自己用的

如何设置其大小:

堆内存:默认大小为范围为 物理内存的 1/64 - 1/4;

默认剩余内存小于最小内存40%时自动扩充到最大内存 , 剩余 内存大于最大内存的70%自动缩小的最小内存

最小内存由 -Xms 设置,最大内存由-Xmx 设置

非堆内存(也叫持久区):默认范围也是 物理内存的 1/64 - 1/4;

最小内存 -XX:PermSize设置,最大内存 -XX:MaxPermSize 设置

由于存在多线程,对每个线程的栈大小也有设定:jdk5.0以后默认是1M,以前默认256k

由-Xss来设置

设置例子: -server -Xss256k -Xms512m -Xmx512m -XX:PermSize=256m -XX:MaxPermSize=256m

-server是配置服务器的意思,一般用来在tomcat中配置