深入理解jvm:Java内存管理机制

#java虚拟机内存区域

##程序计数器(记录正在执行得虚拟机字节码指令得地址):
线程私有得一块很小得内存。用来记录代码执行得行号。用过程序计数器来选取下一条需要执行得字节码指令。峰值,循环,跳转,异常处理,线程恢复等基础功能都需要以来这个计数器来完成。
##java虚拟机栈
生命周期和线程相同。体现得是java方法得执行内存模型。
每个方法执行时都会创建一个栈帧用于存储“局部变量表”,”操作数栈“,”动态链接“,”方法出口“等信息。一个方法执行得过程就是栈帧在虚拟机栈中进栈和出栈的过程。
java内存常说的栈区其实就是虚拟机栈的一部分(局部变量表部分)。
##局部变量表:
存放编译期可知的各种基本数据类型,对象引用,returenAddress类型。
局部变量表的内存空间在编译期间完成了分配,当进入
一个方法时这个方法需要在帧中分配多大的局部变量内存空间是完全确定的。
java虚拟机栈中会出现两种异常:
***Error异常:线程清秀的栈升读大于虚拟机允许的深度。
OutOfMemoryError异常:虚拟机栈动态扩展的时候无法申请到足够的内存。
##本地方法栈
和虚拟机栈相识。虚拟机栈执行java方法。本地方法栈,执行Native方法服务。
##java堆
java堆是java虚拟机所管理的内存中最大的一块。所有线程共享,用于存放所有的数组和对象实例。
也是垃圾收集器管理的主要区域。如果堆内没有完成实例分配会抛出OutOfMemoryError异常。
堆又可以分为:

  • 新生代:
    GC经常光顾得区域
  • Eden 空间:
    对象创建后放在Eden空间中,当执行GC后,留存下来得对象被复制到To Survivor空间中去。
  • From Survivor空间:
    执行GC过后,当From中存放得对象年龄阈值已经达到了,直接复制到年老中去。否则复制到To中去。
  • To Survivor空间:
    当From空间被清空,则To和From调换位置,如果To区中被填满,则将所有对象放到年老代
  • 年老代:
    相对安全得区域,但是还是会被GC处理。

##方法区
用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。(以前使用永久代来实现方法区,Java8已经将方法区拆分成元空间,静态变量和常量池。其中元空间存放类得元信息在本地内存中,静态变量和常量池等并入堆中)
##运行时常量池
运行时常量池是方法区的一部分。用于存放编译期生成的各种字面量和符号的引用(也可以动态添加,比如String得intern()方法 )。

  • 字面量:相当于Java语言层面常量的概念
  • 引用:类和接口的全限定名,字段名称和描述符,方法名称和描述符

##直接内存
通过Native函数使用NIO直接使用的堆外内存(本机内存)

#内存溢出模拟:
##java堆内存溢出:
1、设置最大堆内存(-Xmx20m -Xms20m -Xmn20m -XX:+HeapDumpOnOutOfMemoryError)

2、无限添加对象

3、执行代码查看内存发,可以发现堆内存急剧增加,并且报java.lang.OutOfMemoryError: Java heap space

##java 栈内存溢出
1、设置栈内存大小为1M (-Xss1m )
2、递归方式无限入栈

3、报栈内存溢出

相关推荐:

如何理解 doctest 中的 “Got nothing” 错误提示

当doctest报错“gotnothing”,意味着被测函数未产生任何可显示的输出(如返回值为none或未显式打印),而预期却有明确输出(如private:80),导致断言失败。 当doctest报错“gotnothing”,意味着被测函数未产生任何可显示的输出(如返回值为none或未显式打印),而...

如何理解 doctest 中的 “Got nothing” 错误及其修复方法

doctest报错“gotnothing”表示函数实际未产生任何可显示的输出(如返回none或无print),但测试用例却期望看到具体值(如'private:80'),本质是返回值与预期不匹配。 doctest报错“gotnothing”表示函数实际未产生任何可显示的输出(如返回none或无prin...

怎么优化Python中的字符串拼接操作以避免频繁的内存分配?

+拼接在循环中特别慢,因字符串不可变,每次s=s+item都新建对象并复制全部内容,时间复杂度达O(n²),引发大量内存分配与垃圾回收;推荐用list.append()+''.join()降至O(n)。 为什么+拼接字符串在循环里特别慢? Python中的字符串是不可变对象,每次用+拼接都会创建新字...

如何解决Python多进程共享大字典时的内存拷贝问题?

直接用dict传给子进程会导致内存翻倍,因fork后的写时复制被Python内部操作(如引用计数、哈希查找)意外触发;共享只读字典应使用shared_memory+序列化,配合显式清理。 直接用dict传给子进程,内存几乎必然翻倍——不是因为你要改它,而是Python解释器自己就在偷偷写它。 为什么...

Python生成器yield关键字怎么理解_掌握惰性求值优化大内存处理

yield将函数变为生成器工厂,调用返回generator对象而非执行结果;与return的本质区别在于:return终止函数并丢弃局部变量,yield暂停函数并完整保留栈帧(含局部变量和执行位置),下次从yield下一行继续。 yield是什么,它和return有什么本质区别 yield不是“暂停...