-
JVM虚拟机
Java程序在运行时都要开辟空间,任何软件在运行时都要在内存中开辟空间,Java虚拟机运行时也是要开辟空间的。JVM运行时在内存中开辟一片内存区域,启动时在自己的内存区域中进行更细致的划分,因为虚拟机中每一片内存处理的方式都不同,所以要单独进行管理。
JVM内存的划分有五片:
1. 寄存器;
2. 本地方法区;
3. 方法区;
4. 栈内存;
5. 堆内存。
-
堆内存和栈内存的概念
1. 堆内存:存储的是数组和对象(其实数组就是对象),凡是new建立的都是在堆中,堆中存放的都是实体(对象),实体用于封装数据,而且是封装多个(实体的多个属性),如果一个数据消失,这个实体也没有消失,还可以用,所以堆是不会随时释放的,但是栈不一样,栈里存放的都是单个变量,变量被释放了,那就没有了。堆里的实体虽然不会被释放,但是会被当成垃圾,Java有垃圾回收机制不定时的收取。
2.栈内存: 栈内存首先是一片内存区域,存储的都是局部变量,凡是定义在方法中的都是局部变量(方法外的是全局变量),for循环内部定义的也是局部变量,是先加载函数才能进行局部变量的定义,所以方法先进栈,然后再定义变量,变量有自己的作用域,一旦离开作用域,变量就会被释放。栈内存的更新速度很快,因为局部变量的生命周期都很短。
例:https://blog.youkuaiyun.com/pt666/article/details/70876410/
-
堆和栈的区别
1.栈内存存储的是局部变量而堆内存存储的是实体;
2.栈内存的更新速度要快于堆内存,因为局部变量的生命周期很短;
3.栈内存存放的变量生命周期一旦结束就会被释放,而堆内存存放的实体会被垃圾回收机制不定时的回收。
4.栈(stack):是一个先进后出的数据结构,先分配的内存必定先释放,通常用于保存方法(函数)中的参数,局部变 量。在java中,所有基本类型和引用类型都是在栈中存储的。栈中数据的生存空间一般在当前的 scopes(就是由{...}括起来的区域)。一般是由系统自动分配,存放函数的参数值,局部变量,自动清除。
堆(heap):1). 是一个可动态申请的内存空间(其记录空闲内存空间的链表由操作系统维护),所谓的动态内存,是 其中的内存在不需要时就可以回收,以分配给新的内存请求,其内存中的数据是无序的,即先分配的 和后分配的内存并没有什么必然的位置关系,释放时也可以先后顺序。
2). 在Java中,使用new XXX()构造出来的对象都在堆中存储,当垃圾回收器检测到某对象未被引用,则 自动销毁该对象。所以,理论上说java中对象的生存空间是没有限制,只要有引用类型指向它,则它 可以在任意地方被使用。
-
堆和栈的优缺点:
堆: JAVA的堆是一个运行时的数据区,堆的优势是可以动态的分配内存大小,生存期也不必事先告诉编译器,因为他是在运行时动态 的分配内存的,JAVA的垃圾回收器会自动回收走这些不用的数据.但缺点是,由于要在运行时动态分配内存,存取速度较慢.
栈: 栈的优势是存取速度比堆快,仅次于寄存器,栈数据可以共享.但缺点是,存在栈中的数据大小和生命周期必须是确定的,缺乏灵活 性.栈中一般存放基本类型(int, short, long, byte, float, double, boolean, char)的变量和对象.
-
栈
栈有一个很重要的特殊性:存在栈中的数据可以共享。比如下面我们定义:
-
堆
http://www.cnblogs.com/iyangyuan/p/4631696.html
String s =new String()分析堆与栈,是先定义S,还是先new string()
1. String str1 = "abc";
System.out.println(str1 == "abc");
步骤:
1) 栈中开辟一块空间存放引用str1;
2) String池中开辟一块空间,存放String常量"abc";
3) 引用str1指向池中String常量"abc";
4) str1所指代的地址即常量"abc"所在地址,输出为true;
2. String str2 = new String("abc");
System.out.println(str2 == "abc");
步骤:
1) 栈中开辟一块空间存放引用str2;
2) 堆中开辟一块空间存放一个新建的String对象"abc";
3) 引用str2指向堆中的新建的String对象"abc";
4) str2所指代的对象地址为堆中地址,而常量"abc"地址在池中,输出为false;
3. String str3 = new String("abc");
System.out.println(str3 == str2);
步骤:
1) 栈中开辟一块空间存放引用str3;
2) 堆中开辟一块新空间存放另外一个(不同于str2所指)新建的String对象;
3) 引用str3指向另外新建的那个String对象 ;
4) str3和str2指向堆中不同的String对象,地址也不相同,输出为false;
4. String str4 = "a" + "b";
System.out.println(str4 == "ab");
步骤:
1) 栈中开辟一块空间存放引用str4;
2) 根据编译器合并已知量的优化功能,池中开辟一块空间,存放合并后的String常量"ab";
3) 引用str4指向池中常量"ab";
4) str4所指即池中常量"ab",输出为true;
5. final String s = "a"; //注意:这里s用final修饰,相当于一个常量
String str5 = s + "b";
System.out.println(str5 == "ab");
步骤:
同四
6. String s1 = "a";
String s2 = "b";
String str6 = s1 + s2;
System.out.println(str6 == "ab");
步骤:
1) 栈中开辟一块中间存放引用s1,s1指向池中String常量"a",
2) 栈中开辟一块中间存放引用s2,s2指向池中String常量"b",
3) 栈中开辟一块中间存放引用str5,
4) s1 + s2通过StringBuilder的最后一步toString()方法还原一个新的String对象"ab",因此堆中开辟一块空间存放此对象,
5) 引用str6指向堆中(s1 + s2)所还原的新String对象,
6) str6指向的对象在堆中,而常量"ab"在池中,输出为false
7. String str7 = "abc".substring(0, 2);
步骤:
1) 栈中开辟一块空间存放引用str7,
2) substring()方法还原一个新的String对象"ab"(不同于str6所指),堆中开辟一块空间存放此对象,
3) 引用str7指向堆中的新String对象,
8. String str8 = "abc".toUpperCase();
步骤:
1) 栈中开辟一块空间存放引用str8,
2) toUpperCase()方法还原一个新的String对象"ABC",池中并未开辟新的空间存放String常量"ABC",
3) 引用str8指向堆中的新String对象
9.String s="abc";
String s1=s;
System.out.println(s1=="abc");
s=s+"hello";
System.out.println(s1=="abc");
System.out.println(s=="abc");
步骤:
1)栈中开辟一块空间存放s;
2)Sting池中开辟一块空间用于存放"abc",栈中开辟一块空间存放变量s1;
3)系统输出true,在堆中开辟一块空间用于存放"abchello";
4)引用s指向堆中的"abchello";
5)系统输出true,然后输出false;
JVM的内存模型
栈内存详解
栈内存是一个先进后出的结构。栈内存又可以称为线程内存,即一个线程会开辟一个栈内存。
栈帧:栈帧是属于虚拟机栈的一部分,栈帧里存储了方法的入口,方法的参数,局部变量,返回地址等。栈顶的栈帧代表了当前正在执行的方法,每一个栈帧都又自己的操作栈,局部变量表等,大概5块数据区域