面试总结-java内存结构和内存模型

内存结构

1.jvm把内存分为4大块,分别是堆,方法区,程序计数器,栈。

  • 程序计数器,栈是每个线程独有的;程序计数器里存的是当前线程的字节码指令执行到的位置,java代码就是通过改变这个程序计数器的值来执行字节码的指令,因此是线程独有;如果执行的是native方法,这个值是un diundefine;

  • 栈,分为java虚拟机栈和本地方法栈,java虚拟机栈存的是基础类型的变量和对象的引用,局部变量等信息,他的出栈入栈就是一个java方法执行的过程。如一段程序,生成一个对象,其中对象是在堆里的分配的内存,对象的引用存在栈里,有方法在传递对象的时候,其实就是传的栈中地址,例如下边这段代码:---------------
    这段代码,new 出来的tm在堆里分配一块内存空间,栈中有指向这块内存地址,假设是1000,在调用change方法时,把tm传递给change方法,因为tm2是局部变量,所以存到栈中,这时1000和1001其实都指向同一块内存tm,所以tm2的内存地址也是1000,之后new了一个tm2,对tm2重新new,所以在堆中分配一块新的内存,栈中tm2的内存地址也变成了他自己的1001;当change方法执行完成后,栈中的数据立即销毁,但堆中的对象数据,需要等待gc。丛这也可以看出java的引用传递。如果程序需要的栈深度大于jvm栈深度时,会报错stackoverflowerror,典型的如递归的时候没有结束递归。如果系统的栈内存大于需要的栈内存,会报错outofmemary

    Test t = new Test();
    TestModel tm = new TestModel();
    t.change(tm);
    
    public void change(TestModel tm2){
    	TestModel tm2 = new TestModel();
    }```
    
    
  • 方法区,方法区为线程共享的一块内存区域,存放的是可以线程共享的,如静态变量,常量,类的信息。

  • 堆。堆是jvm内存分配重要的一块,堆中存放的主要是对象。也是线程共享的,堆中最主要的就是gc机制。

2.gc机制,gc主要发生在堆区;gc把堆区分成年轻代,老年代,永久代三部分;gc由单独

  • 永久代用于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响。
  • 年轻代是gc最活跃的区域,年轻代分为三部分,eden区,Survivor1区和Survivor2区,new出来的对象,除却大对象直接进入老年代外,都首先分配eden区,当eden区满时,对象转移到一个Survivor区,当这个Survivor区满的时候,在转移到另一个Survivor区。。。始终保证两个Survivor区有一个是空的,当Survivor进行15次复制后,存活的数据将放到老年代,当老年代满时,进行一次fullgc;年轻代用的是复制算法,可以保证内存空间的连续性,eden和Survivor区的比例是8:1:1;老年代使用标记整理算法,将垃圾移动到一个端,在对其清理;
  • 判断对象是否存活,是否需要清理的算法有两种,一个是可达性分析:当一个对象没有能到达gcroot点的路径时,表示需要回收,这种算法可以避免循环引用,可以作为gcroot的点比如栈中的对象的引用;另一个是引用计数法,当一个点被引用,这个对象的计数+1,当失去引用则-1,当为0时表示可以回收。
  • 并发处理器:适用于要求响应时间的环境,因为gc过程中不需要停顿
  • 并行处理器:适用于高吞吐量,gc过程中有停顿。
  • -Xss128k:设置每个线程的堆栈大小。
  • -Xmn2g:设置年轻代大小为2G。
  • -Xmx3550m:设置JVM最大可用内存为3550M。
    -Xms3550m:设置JVM促使内存为3550m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
    -XX:MaxPermSize=16m:设置持久代大小为16m。
    -XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
    -XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6
    -XX:MaxTenuringThreshold=0:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论。

内存模型

jvm工作在主内存上,但是每个线程都有自己的工作内存。线程的工作内存里存的是主内存的变量副本和本线程自己的数据,不同线程的工作内存间不能互相访问,线程间的变量传递都需要同步到主内存再从主内存刷到工作线程。
如果想直接操作主内存,需要加volatile关键字,volatile可以把数据强制性的刷到主内存,读数据的时候也强制性的从主内存读,保证了数据的可见行,因为被volatile修饰的关键字,即使不同线程,也都是直接操作主内存,同时volatile禁止了指令重排序,简单理解成volatile前面的语句已经全部执行完成才会执行volatile修饰的部分。
Synchronized的原理,同步方法通过ACC_SYNCHRONIZED关键字隐式的对方法进行加锁。当线程要执行的方法被标注上ACC_SYNCHRONIZED时,需要先获得锁才能执行该方法。
同步代码块通过monitorenter和monitorexit执行来进行加锁。当线程执行到monitorenter的时候要先获得所锁,才能执行后面的方法。当线程执行到monitorexit的时候则要释放锁。
每个对象自身维护这一个被加锁次数的计数器,当计数器数字为0时表示可以被任意线程获得锁。当计数器不为0时,只有获得锁的线程才能再次获得锁。即可重入锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值