在容器中使用Java RAM:五种不丢失内存的方法

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器镜像服务 ACR,镜像仓库100个 不限时长
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: 本文讲的是在容器中使用Java RAM:五种不丢失内存的方法【编者的话】在这篇文章中,我们想分享一些看起来不那么明显的关于在容器内部中Java内存管理和弹性扩展的细节。 您将看到在即将发布的JDK版本中需要注意的问题和重要更新的列表,以及核心难点的现有解决方法。
本文讲的是在容器中使用Java RAM:五种不丢失内存的方法【编者的话】在这篇文章中,我们想分享一些看起来不那么明显的关于在容器内部中Java内存管理和弹性扩展的细节。 您将看到在即将发布的JDK版本中需要注意的问题和重要更新的列表,以及核心难点的现有解决方法。 我们收集了可以提高Java应用程序的资源使用效率的五个最有趣和最有用的问题点。

【3 天烧脑式 Docker 训练营 | 上海站】随着Docker技术被越来越多的人所认可,其应用的范围也越来越广泛。本次培训我们理论结合实践,从Docker应该场景、持续部署与交付、如何提升测试效率、存储、网络、监控、安全等角度进行。

在Docker中对Java Heap内存的限制

最近,社区中正在讨论在Docker容器中运行Java程序时内存限制错误的问题。
screen.png

JVM的内存使用超出Docker容器的cgroups限制时被内核杀死。

解决这个问题,其中的一个改善对策已经在OpenJDK 9中实现:

“在OpenJDK 9中已经添加了一个实验性的变更,JVM能够感知到Java程序正运行在一个容器中,因此可以调整内存的限制。” 可以查看文章 Java 9 Will Adjust Memory Limits if Running with Docker 。
一个新的JVM参数(-XX:+UseCGroupMemoryLimitForHeap)将根据cgroup中的内存限制自动的为Java进程设置 Xmx参数。

在Java 9正式发布前,Xmx限制作为JVM的一个具体明确的启动参数,这将作为一个变通的方案来解决这个问题。在 official OpenJDK repo 中已经有一个pull请求 “a script to set better default Xmx values according to the docker memory limits” 。

Jelastic通过使用与Docker镜像相结合的增强型系统容器虚拟化层来忽略错误的内存限制。在之前我们已经在文章《 Java and Memory Limits in Containers: LXC, Docker and OpenVZ 》中解释过它是如何工作的。

跟踪不在堆中的原生内存使用

当在云中运行Java应用时,注意Java进程的原生内存使用情况同样非常重要,被称为off-heap内存。它可以被用做以下不同目的:

垃圾回收器和JIT优化的Object Graphs在原生内存中被跟踪和储存数据。此外,从JDK8开始,类的名称和字段,方法的字节流,常量池等已经被分配到Metaspace中,也是在JVM堆之外的内存区域中。

因此,为了追求高性能的Java应用可以在原生内存区中分配内存。使用java.nio.ByteBuffer或者第三方的库可以使得应用保存大量的在系统原生I/O操作层面被管理的缓冲区。

默认的情况下,Metaspace的分配只受到原生系统内存的限制。在Docker容器的混合体中使用不正确的内存限制,将会增加应用不确定的风险。限制metadata的大小是重要的,尤其是当你存在OOM的问题时。可以使用参数 -XX:MaxMetaspaceSize来进行限制。

将所有对象都存储在普通的垃圾回收堆内存之外,对于Java应用程序的内存占用空间有何影响并不明显。有一篇很好的文章详细解释了这个问题,并提供了一些如何分析本地内存使用的指导原则: 

“几周之前,我在尝试分析一个运行在Docker中的Java应用(Spring Boot + Infinispan)的内存使用情况时,遇到了一个有趣的问题。Xmx参数被设置为256m,但是在Docker的监控工具中至少有两次使用了更多的内存。” —— Analyzing java memory usage in a Docker container 。
在文章的结尾作者较为风趣的说明:

“我可以说什么作为结论? 好吧,从来没有在同一句话中说“java”和“micro”,我在开玩笑 - 只要记住,在java的中处理内存,Linux和Docker要比看起来更棘手一些。“
为了跟踪原生内存的分配,可以使用(-XX:NativeMemoryTracking=summary)的JVM参数。请注意如果设置了这个参数将使你获得5%~10%的性能提升。

在运行时缩减JVM使用的内存

在Java应用中其它有效降低JVM中内存消耗的方法是在运行时调整可管理的参数,从JDK7u60和JDK8u20开始,MinHeapFreeRatio和MaxHeapFreeRatio参数已经变得更加容易的被管理。这意味着我们可以在运行时改天它们的值,而无需重新启动Java进程。

在文章《 Runtime Committed Heap Resizing 》中,作者介绍了如何减少内存使用来调整这些可管理的选项:

“……多次调整内存使用的大小,堆容量从159MB增加到444MB。 描述堆容量值的85%应该是已经被释放的,并且指出JVM调整堆的大小可以获得最多15%的使用率。“
这种方法可以为变量加载带来显着的资源使用优化。 而改进JVM内存大小调整的下一步可以允许在运行时模式下更改Xmx,而不需要重新启动Java进程。

提高内存的压缩率

在多数情况下,客户希望最大程度地减少Java应用程序中使用的内存量,从而可以更频繁的GC。例如,这样可以帮助在开发、测试和编译环境中更高效的利用资源来节省资金,同样在生产环境中也适用。然而,根据官方的增强版本说明,当前的GC算法需要多次完整的GC周期来释放全部未被使用的内存。

作为改进,JDK9中增加了一个新可以控制GC算法的的JVM参数(-XX:+ShrinkHeapInSteps)。这个设置将屏蔽4轮完整的GC循环。这样将更加迅速的释放未被使用的内存同时也可以使应用中的变量加载可以最小的使用Java的堆空间。 

减少内存使用速度以便更快速的流动

实时迁移消耗大量内存的Java应用往往需要大量的时间。为了降低总的迁移时间和资源的消耗,迁移引擎通常使用小规模的数据量在服务器之间进行传输。 可以在实时传输前通过压缩RAM来帮助全部GC循环。对于各种应用来说,这种方法可以更具成本效益,以克服在GC循环期间的性能下降,而不是使用未压缩的RAM进行迁移。

我们发现了与此主题相关的伟大研究工作:  GC-assisted JVM Live Migration for Java Server Applications 。作者将JVM与CRIU(检查点/用户空间中的恢复点)集成,并引入了一个新的GC逻辑,以减少Java应用程序从一个主机迁移到另一个主机的时间。所提供的方法允许在执行Java进程状态的快照之前启用迁移感知垃圾收集,然后通过在磁盘上检查它来冻结运行的容器,然后从冻结的角度恢复容器。

此外,Docker社区将 CRIU 整合为主流。目前这个功能还处于试验阶段。 

两者(Java和CRIU)的结合可以释放尚未发现的性能和部署优化的机会,从而改进云中的Java应用程序托管。您可以在文章“ Containers Live Migration: Behind the Scenes ”中找到有关容器在云中如何运行的更多细节。

Java是伟大的,已经在云中很好地运行,特别是在容器中,但是我们认为它可以更好。因此,在本文中,我们介绍了一系列当前可能已经改进的问题,以便顺利,高效地运行Java应用程序。

在Jelastic,我们在全球数百个数据中心运行了数千个Java容器。良好的内存管理对我们至关重要。这就是为什么我们不断将Java内存使用的提高纳入我们的平台,所以开发人员不必明确地处理这些问题。 在Jelastic增强平台上运行Java容器的实验 。 

原文链接:Java RAM Usage in Containers: Top 5 Tips Not to Lose Your Memory(翻译:李强)

原文发布时间为:2017-05-27

本文作者:李强

本文来自云栖社区合作伙伴Dockerone.io,了解相关信息可以关注Dockerone.io。

原文标题:在容器中使用Java RAM:五种不丢失内存的方法

相关文章
|
5天前
|
存储 Java 编译器
Java内存模型(JMM)深度解析####
本文深入探讨了Java内存模型(JMM)的工作原理,旨在帮助开发者理解多线程环境下并发编程的挑战与解决方案。通过剖析JVM如何管理线程间的数据可见性、原子性和有序性问题,本文将揭示synchronized关键字背后的机制,并介绍volatile关键字和final关键字在保证变量同步与不可变性方面的作用。同时,文章还将讨论现代Java并发工具类如java.util.concurrent包中的核心组件,以及它们如何简化高效并发程序的设计。无论你是初学者还是有经验的开发者,本文都将为你提供宝贵的见解,助你在Java并发编程领域更进一步。 ####
|
15天前
|
缓存 easyexcel Java
Java EasyExcel 导出报内存溢出如何解决
大家好,我是V哥。使用EasyExcel进行大数据量导出时容易导致内存溢出,特别是在导出百万级别的数据时。以下是V哥整理的解决该问题的一些常见方法,包括分批写入、设置合适的JVM内存、减少数据对象的复杂性、关闭自动列宽设置、使用Stream导出以及选择合适的数据导出工具。此外,还介绍了使用Apache POI的SXSSFWorkbook实现百万级别数据量的导出案例,帮助大家更好地应对大数据导出的挑战。欢迎一起讨论!
116 1
|
14天前
|
Kubernetes 监控 Cloud Native
|
4天前
|
存储 缓存 安全
Java内存模型(JMM):深入理解并发编程的基石####
【10月更文挑战第29天】 本文作为一篇技术性文章,旨在深入探讨Java内存模型(JMM)的核心概念、工作原理及其在并发编程中的应用。我们将从JMM的基本定义出发,逐步剖析其如何通过happens-before原则、volatile关键字、synchronized关键字等机制,解决多线程环境下的数据可见性、原子性和有序性问题。不同于常规摘要的简述方式,本摘要将直接概述文章的核心内容,为读者提供一个清晰的学习路径。 ####
16 2
|
5天前
|
存储 安全 Java
什么是 Java 的内存模型?
Java内存模型(Java Memory Model, JMM)是Java虚拟机(JVM)规范的一部分,它定义了一套规则,用于指导Java程序中变量的访问和内存交互方式。
18 1
|
11天前
|
存储 运维 Java
💻Java零基础:深入了解Java内存机制
【10月更文挑战第18天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
21 1
|
13天前
|
机器学习/深度学习 算法 物联网
大模型进阶微调篇(一):以定制化3B模型为例,各种微调方法对比-选LoRA还是PPO,所需显存内存资源为多少?
本文介绍了两种大模型微调方法——LoRA(低秩适应)和PPO(近端策略优化)。LoRA通过引入低秩矩阵微调部分权重,适合资源受限环境,具有资源节省和训练速度快的优势,适用于监督学习和简单交互场景。PPO基于策略优化,适合需要用户交互反馈的场景,能够适应复杂反馈并动态调整策略,适用于强化学习和复杂用户交互。文章还对比了两者的资源消耗和适用数据规模,帮助读者根据具体需求选择最合适的微调策略。
|
13天前
|
缓存 监控 Java
在使用 Glide 加载 Gif 动画时避免内存泄漏的方法
【10月更文挑战第20天】在使用 Glide 加载 Gif 动画时,避免内存泄漏是非常重要的。通过及时取消加载请求、正确处理生命周期、使用弱引用、清理缓存和避免重复加载等方法,可以有效地避免内存泄漏问题。同时,定期进行监控和检测,确保应用的性能和稳定性。需要在实际开发中不断积累经验,根据具体情况灵活运用这些方法,以保障应用的良好运行。
|
14天前
|
存储 算法 Java
Java虚拟机(JVM)的内存管理与性能优化
本文深入探讨了Java虚拟机(JVM)的内存管理机制,包括堆、栈、方法区等关键区域的功能与作用。通过分析垃圾回收算法和调优策略,旨在帮助开发者理解如何有效提升Java应用的性能。文章采用通俗易懂的语言,结合具体实例,使读者能够轻松掌握复杂的内存管理概念,并应用于实际开发中。
|
21天前
|
存储 监控 算法
Java中的内存管理与垃圾回收机制解析
本文深入探讨了Java编程语言中的内存管理方式,特别是垃圾回收机制。我们将了解Java的自动内存管理是如何工作的,它如何帮助开发者避免常见的内存泄漏问题。通过分析不同垃圾回收算法(如标记-清除、复制和标记-整理)以及JVM如何选择合适的垃圾回收策略,本文旨在帮助Java开发者更好地理解和优化应用程序的性能。

热门文章

最新文章