美文网首页
Java内存区域

Java内存区域

作者: lbcBoy | 来源:发表于2020-05-21 14:26 被阅读0次
  • 程序计数器
    线程私有,生命周期与线程相同。
    当前线程所执行字节码的行号指示器。
    分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
    没有OutOfMemory

    java的多线程是通过线程轮流切换分配处理器执行时间的方式来实现的。

  • 虚拟机栈
    描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。

  • 本地方法栈
    本地方法栈为虚拟机使用的Native方法服务

  • 堆 (线程共享)
    唯一的目的:存放对象实例
    可细分为新生代、老年代,再细致一点的有Eden空间、From Survivor空间、To Survivor空间等。
    Java堆中可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)

      问题:多线程中的ThreadLocal和TLAB什么关系?
      答:不一样
      TLAB(Thread Local Allocation Buffer)
      1.堆是JVM中所有线程共享的,因此在其上进行对象内存的分配均需要进行加锁,这也导致了new对象的开销是比较大的。
      2.Sun Hotspot JVM为了提升对象内存分配的效率,对于所创建的线程都会分配一块独立的空间TLAB(Thread Local Allocation Buffer)。
      其大小由JVM根据运行的情况计算而得,在TLAB上分配对象时不需要加锁,因此JVM在给线程的对象分配内存时会尽量的在TLAB上分配 。
      在这种情况下JVM中分配对象内存的性能和C基本是一样高效的,但如果对象过大的话则仍然是直接使用堆空间分配
      3.TLAB仅作用于新生代的Eden Space,因此在编写Java程序时,通常多个小的对象比大的对象分配起来更加高效。
      4.所有新创建的Object 都将会存储在新生代Yong Generation中。
     如果Young Generation的数据在一次或多次GC后存活下来,那么将被转移到OldGeneration。
     新的Object总是创建在Eden Space。
    
  • 方法区(线程共享)
    用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
    运行时常量池是方法区的一部分。

  • 直接内存(Direct Memory)
    并不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域。
    在JDK1.4中新加入了NIO类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。

**句柄 vs 直接指针**
句柄中指向的是到对象实例数据的指针;
直接指针中指向的是对象的实例数据;
他们本质都是指针,使用句柄带来的最大好处就是稳定,使用直接指针速度更快。

**内存溢出 vs 内存泄露**
内存泄漏(memory leak),在大型的、复杂的应用程序中,内存泄漏是常见的问题。
当以前分配的一片内存不再需要使用或无法访问时,但是却并没有释放它,那么对于该进程来说,会因此导致总可用内存的减少,这时就出现了内存泄漏。
尽管优秀的编程实践可以确保最少的泄漏,但是根据经验,当使用大量的函数对相同的内存块进行处理时,很可能会出现内存泄漏。
尤其是在碰到错误路径的情况下更是如此。

一般我们常说的内存泄漏是指堆内存的泄漏。
堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显式释放的内存。        
应用程序一般使用malloc,realloc,new等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free或delete释放该内存块,
否则,这块内存就不能被再次使用,我们就说这块内存泄漏了。

总结:**内存泄露就是堆内存分配的对象空间,没有被GC正常回收,导致内存释放不了,最终会导致内存不足,溢出**

相关文章

网友评论

      本文标题:Java内存区域

      本文链接:https://www.haomeiwen.com/subject/crmgohtx.html