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中配置