理解JVM(2) 栈内存,方法区,堆内存
2017-09-18 11:47
281 查看
堆,方法区,栈的关系
分配最大堆内存-Xmx32m
class SimpleHeap(val id: Int){ fun show() = println("My id is $id") } fun main(args: Array<String>) { val s1 = SimpleHeap(1) val s2 = SimpleHeap(2) s1.show() s2.show() }
方法区内保存类的基本信息,包括方法的实现。方法区里面的信息很少清除
Java堆内保存着s1,s2的实例
Java栈内保存着s1和s2的方法show()的局部变量
栈的溢出测试
栈帧包括:局部变量表(原生类型或引用类型的对象引用),操作数栈(类似于寄存器结构,用于计算),帧数据区(常量池指针和异常处理表)
分配最大栈内存-Xss228K
var count = 0 class SimpleHeap{ fun show(){ count++ val KB = ByteArray(1024*10) KB.set(count, count.toByte()); show() } }
上面代码,我以为是保存了10K的局部变量,后来发现数组还是放在堆内存里面的,栈中只保存一个引用。所以还是能递归3000次吧
var count = 0 class SimpleHeap{ fun show(){ count++ val a = 1L val b = 2L val c = 3L val d = 4L val e = 5L val f = 6L val g = 7L val h = 8L val i = 9L val j = 10L show() } }
一共调用670次,每次调用会使用350个字节,然后局部变量会保存80字节的long型局部变量
堆内存回收分析
class SimpleHeap{ fun gc1(){ val MB = ByteArray(1024*1024*6) System.gc() //不会马上回收内存 } fun gc2(){ var MB: ByteArray? = ByteArray(1024*1024*6) MB = null System.gc() } fun gc3(){ { var MB = ByteArray(1024*1024*6) } System.gc() } fun gc4(){ { var MB = ByteArray(1024*1024*6) } val c = 10 System.gc() } fun gc5(){ gc1() System.gc() } }
gc1()
可以看到没有回收内存。
gc2()
可以发现,又多分配了6MB,然后马上回收,这次一次性回收了12MB,因为gc1()的6MB也给回收了。
gc3(),gc4(),gc5()
gc3()gc4()不能为什么,根本没有分配内存,说不定给Kotlin编译器给优化了。
gc5()在gc1()退出作用域后,直接回收掉了6MB
栈上分配内存
对于那些线程私有的对象(指不会被其他线程访问到的对象),可以打散分配在栈上,而不是分配在堆上。在函数调用后自行下载,而不用垃圾收集器。
实现的技术是进行逃逸分析-XX:+DoEscapeAnalysis
/* -server -Xmx10m -Xms10m -XX:+PrintGC -XX:+DoEscapeAnalysis -XX:-UseTLAB -XX:+EliminateAllocations */ class OnStackTest{ class User(val id:Int = 0, val name:String = ""){ } companion object { fun alloc(){ val u = User(5,"owen") } } } fun main(args: Array<String>) { val b = System.currentTimeMillis() for (i in 0..1000000000){ OnStackTest.alloc() } val c = System.currentTimeMillis() println(c - b) }
要调用100000000次,按理说会频繁调用GC,但栈上分配技术显示, 咳咳,按理说是看不到GC日志
[GC (Allocation Failure) 2047K->544K(9728K), 0.0032233 secs] [GC (Allocation Failure) 2592K->472K(11776K), 0.0080457 secs] 60
方法区
保存系统的类信息,比如类的字段,方法,常量池。
Java1.6,1.7可以理解为永久代(Perm),设置参数为-XX:PermSize=5m,-XX:MaxPermSize=5m
Java1.8中变成了元数据区,使用-XX:MaxMetaspaceSize指定,这是一块堆外的直接内存,如果不指定大小,虚拟机会耗尽所有系统的可用内存
相关文章推荐
- java零碎要点001--深入理解JVM_Java的堆内存_栈内存_以及运行时数据区的作用
- 关于堆内存,栈内存,方法区的解析
- java堆内存、栈内存、方法区
- Jvm(27.14.2),理解升级---堆,栈,方法区
- 如何理解java中的堆内存和栈内存
- 理解java中的栈内存与堆内存
- JVM 线程工作理解和Java静态方法的线程安全性问题
- 深入理解JVM方法调用的内部机制
- 栈、堆内存到底是如何申请的,方法是如何入栈出栈的——内存结构理解学习
- 深入理解JVM : class文件结构之类信息描述、字段表、方法表(2)
- JVM方法区理解
- Jvm(33),理解升级----有一点豁然开朗的的对堆栈方法区的理解
- Java第三课 Java中包的概念,类的说明符、方法的说明符、对象的销毁(JVM垃圾会受器的演示),Java中接口理解与掌握。
- 牛客网Java刷题知识点之内存的划分(寄存器、本地方法区、方法区、栈内存和堆内存)
- Java中jvm的堆内存和栈内存
- 栈、堆内存到底是如何申请的,方法是如何入栈出栈的——内存结构理解学习
- 深入理解JVM笔记之内存管理机制
- JVM【第十三回】:【Java对象存活------finalize()方法】
- 启动 Eclipse 弹出“Failed to load the JNI shared library jvm.dll”错误的解决方法!
- 【JVM】Java中的JavaCore/HeapDump文件及其分析方法