0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Java进程所使用的内存情况介绍

openEuler 来源:openEuler 作者:openEuler 2022-10-12 11:51 次阅读

0.引言

我们经常会好奇,我启动了一个 JVM,他到底会占据多大的内存?他的内存都消耗在哪里?为什么 JVM 使用的内存比我设置的 -Xmx 大这么多?我的内存设置参数是否合理?为什么我的 JVM 内存一直缓慢增长?为什么我的 JVM 会被 OOMKiller 等等,这都涉及到 JAVA 虚拟机对内存的一个使用情况,不如让我们来一探其中究竟。

1.简介

除去大家都熟悉的可以使用 -Xms、-Xmx 等参数设置的堆(Java Heap),JVM 还有所谓的非堆内存(Non-Heap Memory)。

可以通过一张图来简单看一下 Java 进程所使用的内存情况(简略情况):

b309c9c2-494c-11ed-a3b6-dac502259ad0.png

非堆内存包括方法区和Java虚拟机内部做处理或优化所需的内存。

方法区:在所有线程之间共享,存储每个类的结构,如运行时常量池、字段和方法数据,以及方法和构造函数的代码。方法区在逻辑上(虚拟机规范)是堆的一部分,但规范并不限定实现方法区的内存位置和编译代码的管理策略,所以不同的 Java 虚拟机可能有不同的实现方式,此处我们仅讨论 HotSpot。

除了方法区域外,Java 虚拟机实现可能需要内存用于内部的处理或优化。例如,JIT编译器需要内存来存储从Java虚拟机代码转换的本机代码(储存在CodeCache中),以获得高性能。

从 OpenJDK8 起有了一个很 nice 的虚拟机内部功能:Native Memory Tracking (NMT) 。我们可以使用 NMT 来追踪了解 JVM 的内存使用详情(即上图中的 JVM Memory 部分),帮助我们排查内存增长与内存泄漏相关的问题。

2.如何使用

2.1 开启 NMT

默认情况下,NMT是处于关闭状态的,我们可以通过设置 JVM 启动参数来开启:-XX:NativeMemoryTracking=[off | summary | detail]。

注意:启用NMT会导致5% -10%的性能开销。

NMT 使用选项如下表所示:

NMT 选项 说明
off 不跟踪 JVM 本地内存使用情况。如果不指定 -XX:NativeMemoryTracking 选项则默认为off。
summary 仅跟踪 JVM 子系统(如:Java heap、class、code、thread等)的内存使用情况。
detail 除了通过 JVM 子系统跟踪内存使用情况外,还可以通过单独的 CallSite、单独的虚拟内存区域及其提交区域来跟踪内存使用情况。

我们注意到,如果想使用 NMT 观察 JVM 的内存使用情况,我们必须重启 JVM 来设置 XX:NativeMemoryTracking 的相关选项,但是重启会使得我们丢失想要查看的现场,只能等到问题复现时才能继续观察。

笔者试图通过一种不用重启 JVM 的方式来开启 NMT ,但是很遗憾目前没有这样的功能。

JVM 启动后只有被标记为 manageable 的参数才可以动态修改或者说赋值,我们可以通过 JDK management interface (com.sun.management.HotSpotDiagnosticMXBean API) 或者 jinfo -flag 命令来进行动态修改的操作,让我们看下所有可以被修改的参数值(JDK8):

java-XX:+PrintFlagsFinal|grepmanageable

intxCMSAbortablePrecleanWaitMillis=100{manageable}
intxCMSTriggerInterval=-1{manageable}
intxCMSWaitDuration=2000{manageable}
boolHeapDumpAfterFullGC=false{manageable}
boolHeapDumpBeforeFullGC=false{manageable}
boolHeapDumpOnOutOfMemoryError=false{manageable}
ccstrHeapDumpPath={manageable}
uintxMaxHeapFreeRatio=100{manageable}
uintxMinHeapFreeRatio=0{manageable}
boolPrintClassHistogram=false{manageable}
boolPrintClassHistogramAfterFullGC=false{manageable}
boolPrintClassHistogramBeforeFullGC=false{manageable}
boolPrintConcurrentLocks=false{manageable}
boolPrintGC=false{manageable}
boolPrintGCDateStamps=false{manageable}
boolPrintGCDetails=false{manageable}
boolPrintGCID=false{manageable}
boolPrintGCTimeStamps=false{manageable}

很显然,其中不包含 NativeMemoryTracking 。

2.2 使用 jcmd 访问 NMT 数据

我们可以通过jcmd命令来很方便的查看 NMT 相关的数据:

jcmdVM.native_memory[summary|detail|baseline|summary.diff|detail.diff|shutdown][scale=KB|MB|GB]

jcmd 操作 NMT 选项如下表所示:

jcmd NMT 选项 说明
summary 打印按类别汇总的摘要信息
detail 打印按类别汇总的内存使用情况
打印虚拟内存映射
打印按 call site 汇总的内存使用情况
baseline 创建一个新的内存使用状况的快照,用以进行比较
summary.diff 根据上一个 baseline 基线打印新的 summary 对比报告
detail.diff 根据上一个 baseline 基线打印新的 detail 对比报告
shutdown 停止NMT

NMT 默认打印的报告是 KB 来进行呈现的,为了满足我们不同的需求,我们可以使用scale=MB | GB来更加直观的打印数据。

创建 baseline 之后使用 diff 功能可以很直观地对比出两次 NMT 数据之间的差距。

看到 shutdown 选项,笔者本能的一激灵,既然我们可以通过 shutdown 来关闭 NMT ,那为什么不能通过逆向 shutdown 功能来动态的开启 NMT 呢?笔者找到 shutdown 相关源码(以下都是基于 OpenJDK 8):

#hotspot/src/share/vm/services/nmtDCmd.cpp
voidNMTDCmd::execute(DCmdSourcesource,TRAPS){

//CheckNMTstate
//nativememorytrackinghastobeon
if(MemTracker::tracking_level()==NMT_off){
output()->print_cr("Nativememorytrackingisnotenabled");
return;
}elseif(MemTracker::tracking_level()==NMT_minimal){
output()->print_cr("Nativememorytrackinghasbeenshutdown");
return;
}

......
//执行shutdown操作
elseif(_shutdown.value()){
MemTracker::shutdown();
output()->print_cr("Nativememorytrackinghasbeenturnedoff");
}
......

}

#hotspot/src/share/vm/services/memTracker.cpp
//ShutdowncanonlybeissuedviaJCmd,andNMTJCmdisserializedbylock
voidMemTracker::shutdown(){
//WecanonlyshutdownNMTtominimaltrackinglevelifitiseveron.
if(tracking_level()>NMT_minimal){
transition_to(NMT_minimal);
}
}

#hotspot/src/share/vm/services/nmtCommon.hpp
//Nativememorytrackinglevel//NMT的追踪等级
enumNMT_TrackingLevel{
NMT_unknown=0xFF,
NMT_off=0x00,
NMT_minimal=0x01,
NMT_summary=0x02,
NMT_detail=0x03
};

遗憾的是通过源码我们发现,shutdown 操作只是将 NMT 的追踪等级 tracking_level 变成了 NMT_minimal 状态(而并不是直接变成了 off 状态),注意注释:We can only shutdown NMT to minimal tracking level if it is ever on(即我们只能将NMT关闭到最低跟踪级别,如果它曾经打开)。

这就导致了如果我们没有开启过 NMT ,那就没办法通过魔改 shutdown 操作逆向打开 NMT ,因为 NMT 追踪的部分内存只在 JVM 启动初始化的阶段进行记录(如在初始化堆内存分配的过程中通过 NMT_TrackingLevel level = MemTracker::tracking_level(); 来获取 NMT 的追踪等级,视等级来记录内存使用情况),JVM 启动之后再开启 NMT 这部分内存的使用情况就无法记录,所以目前来看,还是只能在重启 JVM 后开启 NMT。

至于提供 shutdown 功能的原因,应该就是让用户在开启 NMT 功能之后如果想要关闭,不用再次重启 JVM 进程。shutdown 会清理虚拟内存用来追踪的数据结构,并停止一些追踪的操作(如记录 malloc 内存的分配)来降低开启 NMT 带来的性能耗损,并且通过源码可以发现 tracking_level 变成 NMT_minimal 状态后也不会再执行 jcmd VM.native_memory 命令相关的操作。

2.3 虚拟机退出时获取 NMT 数据

除了在虚拟机运行时获取 NMT 数据,我们还可以通过两个参数:-XX:+UnlockDiagnosticVMOptions和-XX:+PrintNMTStatistics,来获取虚拟机退出时内存使用情况的数据(输出数据的详细程度取决于你设定的跟踪级别,如 summary/detail 等)。

-XX:+UnlockDiagnosticVMOptions:解锁用于诊断 JVM 的选项,默认关闭。
-XX:+PrintNMTStatistics:当启用 NMT 时,在虚拟机退出时打印内存使用情况,默认关闭,需要开启前置参数 -XX:+UnlockDiagnosticVMOptions 才能正常使用。

3.NMT 内存 & OS 内存概念差异性

我们可以做一个简单的测试,使用如下参数启动 JVM :

-Xmx1G-Xms1G-XX:+UseG1GC-XX:MaxMetaspaceSize=256m-XX:MaxDirectMemorySize=256m-XX:ReservedCodeCacheSize=256M-XX:NativeMemoryTracking=detail

然后使用 NMT 查看内存使用情况(因各环境资源参数不一样,部分未明确设置数据可能由虚拟机根据资源自行计算得出,以下数据仅供参考):

jcmdVM.native_memorydetail

NMT 会输出如下日志:

NativeMemoryTracking:

Total:reserved=2813709KB,committed=1497485KB
-JavaHeap(reserved=1048576KB,committed=1048576KB)
(mmap:reserved=1048576KB,committed=1048576KB)

-Class(reserved=1056899KB,committed=4995KB)
(classes#442)
(malloc=131KB#259)
(mmap:reserved=1056768KB,committed=4864KB)

-Thread(reserved=258568KB,committed=258568KB)
(thread#127)
(stack:reserved=258048KB,committed=258048KB)
(malloc=390KB#711)
(arena=130KB#234)

-Code(reserved=266273KB,committed=4001KB)
(malloc=33KB#309)
(mmap:reserved=266240KB,committed=3968KB)

-GC(reserved=164403KB,committed=164403KB)
(malloc=92723KB#6540)
(mmap:reserved=71680KB,committed=71680KB)

-Compiler(reserved=152KB,committed=152KB)
(malloc=4KB#36)
(arena=148KB#21)

-Internal(reserved=14859KB,committed=14859KB)
(malloc=14827KB#3632)
(mmap:reserved=32KB,committed=32KB)

-Symbol(reserved=1423KB,committed=1423KB)
(malloc=936KB#111)
(arena=488KB#1)

-NativeMemoryTracking(reserved=330KB,committed=330KB)
(malloc=118KB#1641)
(trackingoverhead=211KB)

-ArenaChunk(reserved=178KB,committed=178KB)
(malloc=178KB)

-Unknown(reserved=2048KB,committed=0KB)
(mmap:reserved=2048KB,committed=0KB)

......

大家可能会发现 NMT 所追踪的内存(即 JVM 中的 Reserved、Committed)与操作系统 OS (此处指Linux)的内存概念存在一定的差异性。

首先按我们理解的操作系统的概念:

操作系统对内存的分配管理典型地分为两个阶段:保留(reserve)和提交(commit)。保留阶段告知系统从某一地址开始到后面的dwSize大小的连续虚拟内存需要供程序使用,进程其他分配内存的操作不得使用这段内存;提交阶段将虚拟地址映射到对应的真实物理内存中,这样这块内存就可以正常使用[1]。

如果使用 top 或者 smem 等命令查看刚才启动的 JVM 进程会发现:

top

PIDUSERPRNIVIRTRESSHRS%CPU%MEMTIME+COMMAND
36257dou+20010.8g5420017668S99.70.013:04.15java

此时疑问就产生了,为什么 NMT 中的 committed ,即日志详情中 Total: reserved=2813709KB, committed=1497485KB 中的 1497485KB 与 top 中 RES 的大小54200KB 存在如此大的差异?

使用 man 查看 top 中 RES 的概念(不同版本 Linux 可能不同):

RES--ResidentMemorySize(KiB)
Asubsetofthevirtualaddressspace(VIRT)representingthenon-swappedphysicalmemoryataskiscurrentlyusing.ItisalsothesumoftheRSan,
RSfdandRSshfields.

Itcanincludeprivateanonymouspages,privatepagesmappedtofiles(includingprogramimagesandsharedlibraries)plussharedanonymouspages.
AllsuchmemoryisbackedbytheswapfilerepresentedseparatelyunderSWAP.

Lastly,thisfieldmayalsoincludesharedfile-backedpageswhich,whenmodified,actasadedicatedswapfileandthuswillneverimpactSWAP.

RES 表示任务当前使用的非交换物理内存(此时未发生swap),那按对操作系统 commit 提交内存的理解,这两者貌似应该对上,为何现在差距那么大呢?

笔者一开始猜测是 JVM 的 uncommit 机制(如 JEP 346[2],支持 G1 在空闲时自动将 Java 堆内存返回给操作系统,BiSheng JDK 对此做了增强与改进[3])造成的,JVM 在 uncommit 将内存返还给 OS 之后,NMT 没有除去返还的内存导致统计错误。

但是在翻阅了源码之后发现,G1 在 shrink 缩容的时候,通常调用链路如下:

G1CollectedHeap::shrink->
G1CollectedHeap::shrink_helper->
HeapRegionManager::shrink_by->
HeapRegionManager::uncommit_regions->
G1PageBasedVirtualSpace::uncommit->
G1PageBasedVirtualSpace::uncommit_internal->
os::uncommit_memory

忽略细节,uncommit 会在最后调用 os::uncommit_memory ,查看 os::uncommit_memory 源码:

boolos::uncommit_memory(char*addr,size_tbytes){
boolres;
if(MemTracker::tracking_level()>NMT_minimal){
Trackertkr=MemTracker::get_virtual_memory_uncommit_tracker();
res=pd_uncommit_memory(addr,bytes);
if(res){
tkr.record((address)addr,bytes);
}
}else{
res=pd_uncommit_memory(addr,bytes);
}
returnres;
}

可以发现在返还 OS 内存之后,MemTracker 是进行了统计的,所以此处的误差不是由 uncommit 机制造成的。

既然如此,那又是由什么原因造成的呢?笔者在追踪 JVM 的内存分配逻辑时发现了一些端倪,此处以Code Cache(存放 JVM 生成的 native code、JIT编译、JNI 等都会编译代码到 native code,其中 JIT 生成的 native code 占用了 Code Cache 的绝大部分空间)的初始化分配为例,其大致调用链路为下:

InitializeJVM->
Thread::vreate_vm->
init_globals->
codeCache_init->
CodeCache::initialize->
CodeHeap::reserve->
VirtualSpace::initialize->
VirtualSpace::initialize_with_granularity->
VirtualSpace::expand_by->
os::commit_memory

查看 os::commit_memory 相关源码:

boolos::commit_memory(char*addr,size_tsize,size_talignment_hint,
boolexecutable){
boolres=os::pd_commit_memory(addr,size,alignment_hint,executable);
if(res){
MemTracker::record_virtual_memory_commit((address)addr,size,CALLER_PC);
}
returnres;
}

我们发现 MemTracker 在此记录了 commit 的内存供 NMT 用以统计计算,继续查看 os::pd_commit_memory 源码,可以发现其调用了 os::commit_memory_impl 函数。

查看 os::commit_memory_impl 源码:

intos::commit_memory_impl(char*addr,size_tsize,boolexec){
intprot=exec?PROT_READ|PROT_WRITE|PROT_EXEC:PROT_READ|PROT_WRITE;
uintptr_tres=(uintptr_t)::mmap(addr,size,prot,
MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS,-1,0);
if(res!=(uintptr_t)MAP_FAILED){
if(UseNUMAInterleaving){
numa_make_global(addr,size);
}
return0;
}

interr=errno;//saveerrnofrommmap()callabove

if(!recoverable_mmap_error(err)){
warn_fail_commit_memory(addr,size,exec,err);
vm_exit_out_of_memory(size,OOM_MMAP_ERROR,"committingreservedmemory.");
}

returnerr;
}

问题的原因就在 uintptr_t res = (uintptr_t) ::mmap(addr, size, prot, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0); 这段代码上。

我们发现,此时申请内存执行的是 mmap 函数,并且传递的 port 参数是 PROT_READ|PROT_WRITE|PROT_EXEC 或 PROT_READ|PROT_WRITE ,使用 man 查看 mmap ,其中相关描述为:

Theprotargumentdescribesthedesiredmemoryprotectionofthemapping(andmustnotconflictwiththeopenmodeofthefile).ItiseitherPROT_NONE
orthebitwiseORofoneormoreofthefollowingflags:

PROT_EXECPagesmaybeexecuted.

PROT_READPagesmayberead.

PROT_WRITEPagesmaybewritten.

PROT_NONEPagesmaynotbeaccessed.

由此我们可以看出,JVM 中所谓的 commit 内存,只是将内存 mmaped 映射为可读可写可执行的状态!而在 Linux 中,在分配内存时又是 lazy allocation 的机制,只有在进程真正访问时才分配真实的物理内存。所以 NMT 中所统计的 committed 并不是对应的真实的物理内存,自然与 RES 等统计方式无法对应起来。

所以 JVM 为我们提供了一个参数 -XX:+AlwaysPreTouch,使我们可以在启动之初就按照内存页粒度都访问一遍 Heap,强制为其分配物理内存以减少运行时再分配内存造成的延迟(但是相应的会影响 JVM 进程初始化启动的时间),查看相关代码:

voidos::pretouch_memory(char*start,char*end){
for(volatilechar*p=start;p< end; p += os::vm_page_size()) {
    *p = 0;
  }
}

让我们来验证下,开启 -XX:+AlwaysPreTouch 前后的效果。

NMT 的 heap 地址范围:

Virtualmemorymap:
[0x00000000c0000000-0x0000000100000000]reserved1048576KBforJavaHeapfrom
[0x0000ffff93ea36d8]ReservedHeapSpace::ReservedHeapSpace(unsignedlong,unsignedlong,bool,char*)+0xb8
[0x0000ffff93e67f68]Universe::reserve_heap(unsignedlong,unsignedlong)+0x2d0
[0x0000ffff93898f28]G1CollectedHeap::initialize()+0x188
[0x0000ffff93e68594]Universe::initialize_heap()+0x15c

[0x00000000c0000000-0x0000000100000000]committed1048576KBfrom
[0x0000ffff938bbe8c]G1PageBasedVirtualSpace::commit_internal(unsignedlong,unsignedlong)+0x14c
[0x0000ffff938bc08c]G1PageBasedVirtualSpace::commit(unsignedlong,unsignedlong)+0x11c
[0x0000ffff938bf774]G1RegionsLargerThanCommitSizeMapper::commit_regions(unsignedint,unsignedlong)+0x5c
[0x0000ffff93943f54]HeapRegionManager::commit_regions(unsignedint,unsignedlong)+0x7c

对应该地址的/proc/{pid}/smaps:

//开启前//开启后
c0000000-100080000rw-p0000000000:000c0000000-100080000rw-p0000000000:000
Size:1049088kB Size:1049088kB
KernelPageSize:4kBKernelPageSize: 4kB
MMUPageSize: 4kBMMUPageSize: 4kB
Rss: 792kBRss: 1049088kB
Pss:792kBPss: 1049088kB
Shared_Clean: 0kBShared_Clean: 0kB
Shared_Dirty: 0kBShared_Dirty: 0kB
Private_Clean: 0kBPrivate_Clean: 0kB
Private_Dirty: 792kBPrivate_Dirty: 1049088kB
Referenced: 792kBReferenced: 1048520kB
Anonymous: 792kBAnonymous: 1049088kB
LazyFree: 0kBLazyFree: 0kB
AnonHugePages: 0kBAnonHugePages: 0kB
ShmemPmdMapped: 0kBShmemPmdMapped: 0kB
Shared_Hugetlb:0kBShared_Hugetlb: 0kB
Private_Hugetlb:0kBPrivate_Hugetlb: 0kB
Swap:0kBSwap: 0kB
SwapPss:0kBSwapPss: 0kB
Locked:0kBLocked: 0kB
VmFlags:rdwrmrmwmeacVmFlags:rdwrmrmwmeac

对应的/proc/{pid}/status:

//开启前//开启后
......
VmHWM:54136kBVmHWM:1179476kB
VmRSS:54136kBVmRSS:1179476kB
......
VmSwap:0kBVmSwap:0kB
...

开启参数后的 top:

PIDUSERPRNIVIRTRESSHRS%CPU%MEMTIME+COMMAND
85376dou+20010.8g1.1g17784S99.70.414:56.31java

观察对比我们可以发现,开启 AlwaysPreTouch 参数后,NMT 统计的 commited 已经与 top 中的 RES 差不多了,之所以不完全相同是因为该参数只能 Pre-touch 分配 Java heap 的物理内存,至于其他的非 heap 的内存,还是受到 lazy allocation 机制的影响。

同理我们可以简单看下 JVM 的 reserve 机制:

#hotspot/src/share/vm/runtime/os.cpp
char*os::reserve_memory(size_tbytes,char*addr,size_talignment_hint,
MEMFLAGSflags){
char*result=pd_reserve_memory(bytes,addr,alignment_hint);
if(result!=NULL){
MemTracker::record_virtual_memory_reserve((address)result,bytes,CALLER_PC);
MemTracker::record_virtual_memory_type((address)result,flags);
}

returnresult;
}

#hotspot/src/os/linux/vm/os_linux.cpp
char*os::pd_reserve_memory(size_tbytes,char*requested_addr,
size_talignment_hint){
returnanon_mmap(requested_addr,bytes,(requested_addr!=NULL));
}

staticchar*anon_mmap(char*requested_addr,size_tbytes,boolfixed){
......
addr=(char*)::mmap(requested_addr,bytes,PROT_NONE,
flags,-1,0);
......
}

reserve 通过mmap(requested_addr, bytes, PROT_NONE, flags, -1, 0);来将内存映射为 PROT_NONE,这样其他的 mmap/malloc 等就不能调用使用,从而达到了 guard memory 或者说 guard pages 的目的。

OpenJDK 社区其实也注意到了 NMT 内存与 OS 内存差异性的问题,所以社区也提出了相应的 Enhancement 来增强功能:

JDK-8249666[4]:

目前 NMT 将分配的内存显示为 Reserved 或 Committed。而在 top 或 pmap 的输出中,首次使用(即 touch)之前 Reserved 和 Committed 的内存都将显示为 Virtual memory。只有在内存页(通常是4k)首次写入后,它才会消耗物理内存,并出现在 top/pmap 输出的 “常驻内存”(即 RSS)中。

当前NMT输出的主要问题是,它无法区分已 touch 和未 touch 的 Committed 内存。

该 Enhancement 提出可以使用 mincore()[5]来查找 NMT 的 Committed 中 RSS 的部分,mincore() 系统调用让一个进程能够确定一块虚拟内存区域中的分页是否驻留在物理内存中。mincore()已在JDK-8191369 NMT:增强线程堆栈跟踪中实现,需要将其扩展到所有其他类型的内存中(如 Java 堆)。

遗憾的是该 Enhancement 至今仍是 Unresolved 状态。

JDK-8191369[6]:

1 中提到的 NMT:增强线程堆栈跟踪。使用 mincore() 来追踪驻留在物理内存中的线程堆栈的大小,用以解决线程堆栈追踪时有时会夸大内存使用情况的痛点。

该 Enhancement 已经在 JDK11 中实现。

由于内容较多,关于NMT追踪区域分析的内容将在下篇文章进行分享,敬请期待!

审核编辑:彭静
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 内存
    +关注

    关注

    8

    文章

    2800

    浏览量

    73121
  • JAVA
    +关注

    关注

    19

    文章

    2916

    浏览量

    103356
  • 函数
    +关注

    关注

    3

    文章

    4117

    浏览量

    61550
  • 虚拟机
    +关注

    关注

    1

    文章

    870

    浏览量

    27576

原文标题:Native Memory Tracking 详解(1):基础介绍

文章出处:【微信号:openEulercommunity,微信公众号:openEuler】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Java多线程的用法

    本文将介绍一下Java多线程的用法。 基础介绍 什么是多线程 指的是在一个进程中同时运行多个线程,每个线程都可以独立执行不同的任务或操作。 与单线程相比,多线程可以提高程序的并发性和响
    的头像 发表于 09-30 17:07 712次阅读

    Linux 查看进程和删除进程

    ps 命令用于查看当前正在运行的进程。grep 是搜索例如: ps -ef | grep java表示查看所有进程里 CMD 是 java进程
    发表于 04-24 00:04

    Linux上对进程进行内存分析和内存泄漏定位

    在Linux产品开发过程中,通常需要注意系统内存使用量,和评估单一进程内存使用情况,便于我们选取合适的机器配置,来部署我们的产品。Linux本身提供了一些工具方便我们达成这些需求,查
    发表于 07-09 08:15

    linux内存进程查看

    用 'top -i' 看看有多少进程处于 Running 状态,可能系统存在内存或 I/O 瓶颈,用 free 看看系统内存使用情况,swap 是否被占用很多,用 iostat 看看
    发表于 07-16 06:28

    Java程序内存低效使用问题的分析

    Java程序内存的低效使用是导致其性能问题的主要因素。该文分析了泄漏对象、蚍蜉对象和空闲对象3类导致内存低效使用的情况,探讨解决上述问题的方法,并提出构造对象行为模式
    发表于 04-09 09:39 12次下载

    java线程内存模型

    一、Java内存模型 按照官方的说法:Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。 JVM主要管理两种类型
    发表于 09-27 10:55 0次下载
    <b class='flag-5'>java</b>线程<b class='flag-5'>内存</b>模型

    实例分析内存回收机制在java中的应用

    Java中,它的内存管理包括两方面:内存分配(创建Java对象的时候)和内存回收,这两方面工作都是由JVM自动完成的,降低了
    发表于 09-27 15:10 0次下载
    实例分析<b class='flag-5'>内存</b>回收机制在<b class='flag-5'>java</b>中的应用

    Java内存模型及原理分析

    一、Java内存模型 按照官方的说法:Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。 JVM主要管理两种类型
    发表于 09-28 11:49 0次下载
    <b class='flag-5'>Java</b><b class='flag-5'>内存</b>模型及原理分析

    进程间通信之共享内存

    8.5.1 共享内存概述 可以说,共享内存是一种最为高效的进程间通信方式。因为进程可以直接读写内存,不需要任何数据的复制。为了在多个
    发表于 10-18 16:08 1次下载
    <b class='flag-5'>进程</b>间通信之共享<b class='flag-5'>内存</b>

    进程虚拟内存布局以及进程的虚拟内存分配释放流程,涉及的代码

    我们计划通过一系列文章来介绍虚拟内存分配/释放,缺页处理,内存压缩/回收,内存分配器等知识,梳理虚拟内存的管理。本章节结合代码
    的头像 发表于 06-28 09:38 3699次阅读

    java内存溢出的几种原因和解决办法

    Java是一种使用垃圾回收机制的编程语言,由于自动内存管理机制的存在,Java程序中发生内存溢出(Out of Memory)错误的情况相对
    的头像 发表于 11-23 14:44 4330次阅读

    java内存溢出排查方法

    过程中常见的问题之一,可能导致应用程序崩溃、性能下降甚至系统崩溃。在本文中,将详细介绍如何排查和解决Java内存溢出问题。 一、什么是Java内存
    的头像 发表于 11-23 14:46 1008次阅读

    如何查看java程序的内存分布

    要查看Java程序的内存分布,首先需要了解Java程序运行时的内存模型。 Java程序的内存分布
    的头像 发表于 11-23 14:47 718次阅读

    jvm内存分析命令和工具

    介绍JVM内存分析命令和工具,并详细介绍它们的使用方法和功能。 一、JVM内存分析命令 jps命令:jps命令用于显示当前系统中正在运行的Java
    的头像 发表于 12-05 11:07 648次阅读

    java虚拟机内存包括远空间内存

    将详细介绍JVM内存的各个部分及其作用。 Java堆(Heap) Java堆是JVM管理的最大一块内存区域,用于存放
    的头像 发表于 12-05 14:15 232次阅读