java 中的堆栈是什么

java 中的堆栈是什么,第1张

首先堆栈是计算机为程序分配的内存空间,用来存储数据的。

在java中因为我们不直接 *** 作内存,所以并不需要考虑指针的问题

在java中堆和栈也是用来存储数据,其中栈存储的引用,堆存储的对象

如:Student s = new Student("张三");

s在栈中 张三在堆

堆栈是计算机为程序分配的内存空间,用来存储数据的。

内存是计算机系统中一个主要部件, 用于保存进程运行时的程序和数据,也称可执行存储器。在计算机中,内存空间一般是指主存储器空间(物理地址空间)或系统为一个用户程序分配内存空间。扩展内存空间的方法一般有增加内存大小和虚拟内存。

源程序经过汇编或编译后再经过链接编辑程序加工形成的程序的装配模块,及转换为相对地址编址的模块,它是以0为基址顺序进行编址的。

相对地址也称为逻辑地址或虚拟地址,把程序中由相对地址组成的空间叫做逻辑地址空间。相对地址空间通过地址再定位机构转换到绝对地址空间,绝对地址空间也叫物理地址空间。

内存空间一般是指主存储器空间(物理地址空间)或系统为一个用户程序分配内存空间。系统为一个用户程序分配内存空间方法有单一连续分配、固定分区分配、动态分区分配以及动态重定位分区分配四种方式。

为了便于内存分配,通常将分区按大小进行排队,并为之建立一张分区使用表,其中各表项包括每个分区的起始地址、大小及状态(是否已分配)。

当有一用户程序要装入时,由内存分配程序检索该表,从中找出一个能满足要求的、尚未分配的分区,将之分配给该程序,然后将该表项中的状态置为“已分配” ;若未找到大小足够的分区,则拒绝为该用户程序分配内存。

int a=1;

string b="1";

基本类型创建在堆栈中,在内存堆里是没有的。也就是说a就是1,1就是a,你改a就是直接改堆栈里的值。

普通对象用new关键字创建在内存堆里,一个指向内存堆地址的指针(java里叫句柄)赋给变量b。你改对象其实改的是内存堆里的内容,指针本身是没有改变的,但是它指向的内存堆里的内容发生变化

JVM线程堆栈是一个给定时间的快照,它能向你提供所有被创建出来的Java线程的完整清单

每一个被发现的Java线程都会给你如下信息:

– 线程的名称;经常被中间件厂商用来识别线程的标识,一般还会带上被分配的线程池名称以及状态 (运行,阻塞等等)

– 线程类型 & 优先级,例如 : daemon prio=3 中间件程序一般以后台守护的形式创建他们的线程,这意味着这些线程是在后台运行的;它们会向它们的用户提供服务,例如:向你的Java EE应用程序

– Java线程ID,例如 : tid=0x000000011e52a800 这是通过 javalangThreadgetId() 获得的Java线程ID,它常常用自增长的长整形 1n 实现

– 原生线程ID,例如 : nid=0x251c ,之所以关键是因为原生线程ID可以让你获得诸如从 *** 作系统的角度来看那个线程在你的JVM中使用了大部分的CPU时间等这样的相关信息

– Java线程状态和详细信息,例如: waiting for monitor entry [0xfffffffea5afb000] javalangThreadState: BLOCKED (on object monitor)

可以快速的了解到线程状态极其当前阻塞的可能原因

– Java线程栈跟踪;这是目前为止你能从线程堆栈中找到的最重要的数据 这也是你花费最多分析时间的地方,因为Java栈跟踪向提供了你将会在稍后的练习环节了解到的导致诸多类型的问题的根本原因,所需要的90%的信息。

– Java 堆内存分解; 从HotSpot VM 16版本开始,在线程堆栈的末尾处可以看到HotSpot的内存使用情况,比如说Java的堆内存(YoungGen, OldGen) & PermGen 空间。这个信息对分析由于频繁GC而引起的问题时,是很有用的。你可以使用已知的线程数据或模式做一个快速的定位。

Heap

PSYoungGen total 466944K, used 178734K [0xffffffff45c00000, 0xffffffff70800000, 0xffffffff70800000)

eden space 233472K, 76% used [0xffffffff45c00000,0xffffffff50ab7c50,0xffffffff54000000)

from space 233472K, 0% used [0xffffffff62400000,0xffffffff62400000,0xffffffff70800000)

to space 233472K, 0% used [0xffffffff54000000,0xffffffff54000000,0xffffffff62400000)

PSOldGen total 1400832K, used 1400831K [0xfffffffef0400000, 0xffffffff45c00000, 0xffffffff45c00000)

object space 1400832K, 99% used [0xfffffffef0400000,0xffffffff45bfffb8,0xffffffff45c00000)

PSPermGen total 262144K, used 248475K [0xfffffffed0400000, 0xfffffffee0400000, 0xfffffffef0400000)

object space 262144K, 94% used [0xfffffffed0400000,0xfffffffedf6a6f08,0xfffffffee0400000)

线程堆栈信息大拆解

为了让大家更好的理解,给大家提供了下面的这张图,在这张图中将HotSpot VM上的线程堆栈信息和线程池做了详细的拆解,如下图所示:

上图中可以看出线程堆栈是由多个不同部分组成的。这些信息对问题分析都很重要,但对不同的问题模式的分析会使用不同的部分(问题模式会在后面的文章中做模拟和演示。)

现在通过这个分析样例,给大家详细解释一下HoteSpot上线程堆栈信息中的各个组成部分:

# Full thread dump标示符

“Full thread dump”是一个全局唯一的关键字,你可以在中间件和单机版本Java的线程堆栈信息的输出日志中找到它(比如说在UNIX下使用:kill -3 <PID> )。这是线程堆栈快照的开始部分。

Full thread dump Java HotSpot(TM) 64-Bit Server VM (200-b11 mixed mode):

# Java EE 中间件,第三方以及自定义应用软件中的线程

这个部分是整个线程堆栈的核心部分,也是通常需要花费最多分析时间的部分。堆栈中线程的个数取决你使用的中间件,第三方库(可能会有独立线程)以及你的应用程序(如果创建自定义线程,这通常不是一个很好的实践)。

在我们的示例线程堆栈中,WebLogic是我们所使用的中间件。从Weblogic 92开始, 会使用一个用“’weblogickernelDefault (self-tuning)”唯一标识的能自行管理的线程池

"[STANDBY] ExecuteThread: '414' for queue: 'weblogickernelDefault (self-tuning)'" daemon prio=3 tid=0x000000010916a800 nid=0x2613 in Objectwait() [0xfffffffe9edff000]

javalangThreadState: WAITING (on object monitor)

at javalangObjectwait(Native Method)

- waiting on <0xffffffff27d44de0> (a weblogicworkExecuteThread)

at javalangObjectwait(Objectjava:485)

at weblogicworkExecuteThreadwaitForRequest(ExecuteThreadjava:160)

- locked <0xffffffff27d44de0> (a weblogicworkExecuteThread)

at weblogicworkExecuteThreadrun(ExecuteThreadjava:181)

# HotSpot VM 线程

这是一个有Hotspot VM管理的内部线程,用于执行内部的原生 *** 作。一般你不用对此 *** 太多心,除非你(通过相关的线程堆栈以及 prstat或者原生线程Id)发现很高的CPU占用率

"VM Periodic Task Thread" prio=3 tid=0x0000000101238800 nid=0x19 waiting on condition

# HotSpot GC 线程

当使用 HotSpot 进行并行 GC (如今在使用多个物理核心的环境下很常见), 默认创建的HotSpot VM 或者每个JVM管理一个有特定标识的GC线程时 这些GC线程可以让VM以并行的方式执行其周期性的GC清理, 这会导致GC时间的总体减少;与此同时的代价是CPU的使用时间会增加

"GC task thread#0 (ParallelGC)" prio=3 tid=0x0000000100120000 nid=0x3 runnable

"GC task thread#1 (ParallelGC)" prio=3 tid=0x0000000100131000 nid=0x4 runnable

………………………………………………………………………………………………………………………………………………………………

这事非常关键的数据,因为当你遇到跟GC有关的问题,诸如过度GC、内存泄露等问题是,你将可以利用这些线程的原生Id值关联的 *** 作系统或者Java线程,进而发现任何对CPI时间的高占用 未来的文章你将会了解到如何识别并诊断这样的问题

# JNI 全局引用计数

JNI (Java 本地接口)的全局引用就是从本地代码到由Java垃圾收集器管理的Java对象的基本的对象引用 它的角色就是阻止对仍然在被本地代码使用,但是技术上已经不是Java代码中的“活动的”引用了的对象的垃圾收集

同时为了侦测JNI相关的泄露而留意JNI引用也很重要 如果你的程序直接使用了JNI,或者像监听器这样的第三方工具,就容易造成本地的内存泄露

JNI global references: 1925

# Java 堆栈使用视图

这些数据被添加回了 JDK 1 6 ,向你提供有关Hotspot堆栈的一个简短而快速的视图 我发现它在当我处理带有过高CPU占用的GC相关的问题时非常有用,你可以在一个单独的快照中同时看到线程堆栈以及Java堆的信息,让你当时就可以在一个特定的Java堆内存空间中解析(或者排除)出任何的关键点 你如在我们的示例线程堆栈中所见,Java 的堆 OldGen 超出了最大值!

Heap

PSYoungGen total 466944K, used 178734K [0xffffffff45c00000, 0xffffffff70800000, 0xffffffff70800000)

eden space 233472K, 76% used [0xffffffff45c00000,0xffffffff50ab7c50,0xffffffff54000000)

from space 233472K, 0% used [0xffffffff62400000,0xffffffff62400000,0xffffffff70800000)

to space 233472K, 0% used [0xffffffff54000000,0xffffffff54000000,0xffffffff62400000)

PSOldGen total 1400832K, used 1400831K [0xfffffffef0400000, 0xffffffff45c00000, 0xffffffff45c00000)

object space 1400832K, 99% used [0xfffffffef0400000,0xffffffff45bfffb8,0xffffffff45c00000)

PSPermGen total 262144K, used 248475K [0xfffffffed0400000, 0xfffffffee0400000, 0xfffffffef0400000)

object space 262144K, 94% used [0xfffffffed0400000,0xfffffffedf6a6f08,0xfffffffee0400000)

我希望这篇文章能对你理解Hotspot VM线程堆栈的基本信息有所帮助。

Java栈的实现

public class MyStack { //定义一个堆栈类

int[] array; //用int数组来保存数据,根据需要可以换类型

int s_size; //定义堆栈的宽度

public MyStack(int i){ //定义一个带参数构造器

array=new int[i]; //动态定义数组的长度

s_size=0; //堆栈的默认宽度为0

}

public MyStack(){ //默认构造器

this(50); //默认构造器可容纳50个元素

}

public void push(int i){ //压栈

array[thiss_size]=i;

thiss_size++;

}

public int pop(){ //从堆栈中取元素,从栈顶开始取

if(thiss_size!=0){

int t=array[s_size-1]; //用中间变量保存栈顶的元素

array[s_size-1]=0; //取完元素该位置设为0

s_size--; //栈的大小减1

return t; //返回栈顶元素

}else{

Systemoutprintln("This stack is empty"); //当栈为空时显示提示信息,返回0

return 0;

}

}

public boolean isEmpty(){ //判断栈是否为空

return thiss_size==0;

}

public int top(){ //从栈顶取值,功能和 pop() 方法一样

if(!thisisEmpty()){

int t=array[thiss_size-1];

array[thiss_size-1]=0;

thiss_size--;

return t;

}else{

Systemoutprintln("This stack is empty!");

return 0;

}

}

public void printAll(){ //打印出堆栈中的所有元素的值,不是取出,元素依然在堆栈里

if(!thisisEmpty()){

for(int i=thiss_size - 1;i>=0;i--){

Systemoutprintln(array[i]);

}

}

}

//下面是测试代码

public static void main(String[] args){

MyStack stack=new MyStack();

stackpush(4);

stackpush(5);

stackpush(6);

stackpush(7);

//Systemoutprintln(stackisEmpty());

stackprintAll();

Systemoutprintln("===========");

Systemoutprintln(stacktop());

Systemoutprintln(stacktop());

Systemoutprintln(stacktop());

Systemoutprintln(stacktop());

Systemoutprintln(stacktop());

}

}

堆栈是一种数据结构,特点是堆栈中的数据先进后出,或者说后进先出。你可以想象堆栈是个子d夹,先压入的子d放在d夹下面,后压入的子d会在d夹的上面,打q或者卸子d的时候先出上面的子d,下面的子d才能出来。

堆栈会有一个量来标识栈顶,也就是标识出堆栈里最后放进去的数据在什么位置。堆栈可以进行的 *** 作最基本的是两个:一个进栈(push)一个出栈(pop),也有叫压入d出的。进栈的时候要判断栈是否已满,已满的堆栈不能进栈,d夹满了,子d肯定压不进去了。出栈的时候要判断栈是否为空,d夹空了要卸子d肯定是卸不出来的。

以上就是关于java 中的堆栈是什么全部的内容,包括:java 中的堆栈是什么、java中的“堆栈”是什么意思、java基础问题 关于堆栈 基本数据于引用数据类型等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/9525721.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-29
下一篇2023-04-29

发表评论

登录后才能评论

评论列表(0条)

    保存