Java知识学习——虚拟机栈与本地方法栈

虚拟机栈,顾名思义,与我们熟知的数据结构——栈一样。虚拟机栈就是线程运行时所需要的空间,每一个栈内又是以多个栈帧所构成,什么是栈帧?一个栈帧对应了一次方法的调用,即每个方法运行时所需要的内存就是栈帧,方法运行时方法参数、局部变量、返回地址这些都需要占用空间的。栈和栈帧是怎么联系的呢?例如一段代码在执行的时候调用第一个方法,就会给第一个方法分配一个空间并压入栈中,当第一个方法执行完成之后,就会把这个方法对应的栈帧从栈中移除,即释放对应的内存,这就是栈和栈帧之间的关系,一个栈内可以有多个栈帧。

每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法。

垃圾回收是否会管理栈内存?答案是不需要的,因为栈内存无非就是一次次的方法调用所产生的栈帧内存,而栈帧内存在每次方法调用结束之后,都会弹出栈,就是会自动的被回收掉,所以也就是不需要垃圾回收来管理栈内存。垃圾回收主要是回收堆内存的无用对象。

栈内存的分配越大越好吗?栈内存可以通过运行时虚拟机参数来指定(-Xss+大小)。栈内存划分越大反而会使线程数越少 ,物理内存的大小是固定的,例如一个线程使用的是栈内存,一个线程假设使用了1M内存,物理内存假设有500M,理论上我可以有500个线程同时运行,但是如果设置每个线程使用2M的内存,理论上只有250个线程同时运行。所以栈内存并不是划分的越大越好,划分的大只是利于更多的方法递归调用而不会增强运行的效率,反而会影响线程的运行数量。

方法内的局部变量是否是线程安全的?看一个变量是否是线程安全的,其实只需要看它到底是多个线程对这个变量是共享的还是私有的?如果方法内局部变量没有逃离方法的作用范围,它就是线程安全的,反之就可能存在线程安全。如果这个局部变量引用了对象并逃离了方法的作用范围,就需要考虑线程的安全问题。

虚拟机栈中会存在内存溢出,出现内存溢出是有两个方面所引起的:栈帧过多导致(递归调用无结束的条件)和栈帧过大导致。

线程运行的诊断——CPU占用过高。用TOP命令定位哪个进程对CPU过高,用PS命令进一步确认哪个线程引起的CPU过高,最后用jstack +进程ID(Jstack 可以根据线程ID找到有问题的线程,进一步定位到有问题的代码行数,在Jstack里面都是16进制,所以在找的时候需要换算一下)。

线程运行的诊断——程序运行很长时间没有结果。同样是可以采用Jstack命令查看具体的线程问题,以及具体有问题的代码行数。Jstack中也会在最后中显示死锁的信息。

 

本地方法栈,本地方法栈实际上就是在Java虚拟机在调用本地方法时需要给本地方法提供一个内存空间,就是指不是由Java代码编写的方法,Java代码是有一定的限制的,有的时候它不能直接与我们的操作系统底层打交道,所以就需要用C或者C++语言编写的本地方法来与底层操作系统打交道,Java代码可以间接调用本地方法来调用底层的一些功能,本地方法运行的时候所要用到的内存就是我们的本地方法栈。例如Object类中的clone()、hashCode()。

 

猜你喜欢

转载自blog.csdn.net/qq_35363507/article/details/104288779
今日推荐