【编者的话】 如果你尝试在容器中运行Java程序,或者专注于Docker,你可能会遇到一些关于JVM和堆大小的问题。本篇文章将介绍如何解决这些问题。
很多开发者会(或者应该)知道,当我们为运行在Linux容器(Docker、rkt、runC、lxcfs等)中的Java程序去设置JVM的GC、堆大小和运行时编译器的参数时并没有得到预想的效果。当我们通过“java -jar mypplication-fat.jar”的方式而不设置任何参数来运行一个Java应用时,JVM会根据自身的许多参数进行调整,以便在执行环境中获得最优的性能。
本篇博客将通过简单的方式向开发人员展示在将Java应用运行在Linux容器内时需要了解的内容。
我们倾向于认为容器可以像虚拟机一样可以完整的定义虚拟机的CPU个数和虚拟机的内存。容器更像是一个进程级别的资源(CPU、内存、文件系统、网络等)隔离。这种隔离是依赖于Linux内核中提供的一个的功能。
然而,一些可以从运行时环境中收集信息的应用程序在cgroups功能出现之前已经存在。在容器中执行命令 ‘top‘、‘free‘、‘ps’,也包括没有经过优化的JVM是一个会受到高限制的Linux进程。让我们来验证一下。
想要知道为什么是这样的结果,可以去阅读此篇博客文章 “
我们需要知道Docker参数(-m、–memory和–memory-swap)和Kubernetes参数(–limits)会让Linux内核在一个进程的内存超出限制时将其Kill掉,但是JVM根本不清楚这个限制的存在,当超过这个限制时,不好的事情发生了!
在这里我们至少有2个问题:
开发者如果不理解问题可能会认为运行环境中没有为JVM提供足够的内存。通常的解决对策就是为运行环境提供更多的内存,但是实际上,这是一个错误的认识。
应用将会尝试分配超过1.6GB的内存,当超过了容器的限制(800MB的RAM 800MB的Swap),进程将会被Kill掉。
很明显当在容器中运行程序时,通过增加内存和设置JVM的参数不是一个好的方式。当在一个容器中运行Java应用时,我们应该基于应用的需要和容器的限制来设置最大堆大小(参数:-Xmx)。
在Dockerfile中稍作修改,为JVM指定扩展的环境变量。修改内容如下:
Docker下,可以使用“-e”的参数来设置环境变量进行切换。
有什么办法可以根据容器的限制来自动计算Heap的值?
事实上如果你的基础Docker镜像使用的是由Fabric8提供的,那么就可以实现。镜像fabric8/java-jboss-openjdk8-jdk使用了脚本来计算容器的内存限制,并且使用50%的内存作为上限。也就是有50%的内存可以写入。你也可以使用这个镜像来开/关调试、诊断或者其他更多的事情。让我们看一下一个Spring Boot应用的 Dockerfile :
就这样!现在,不管容器的内存限制如何,我们的Java应用将在容器中自动的调节Heap大小,而不是再根据宿主机来设置。
总结到目前为止,Java JVM还不能意识到其是运行在一个容器中 — 某些资源在内存和CPU的使用上会受到限制。因此,你不能让JVM自己来设置其认为的最优的最大Heap值。
一个解决对策是使用Fabric8作为基础镜像,它可以意识到应用程序运行在一个受限制的容器中,并且在你没有做任何事情的情况下,可以自动的调整最大Heap的值。
在JDK9中已经开始进行尝试在容器(i.e. Docker)环境中为JVM提供cgroup功能的内存限制。相关信息可以查看:
原文链接:(翻译:李强)
单击工具栏Run图标右边的下拉箭头,Run As,选中自己的工程名
有些从前做过的工程文件名也在里头,但是这些工程文件实施上已经被删去了。所以才报出“non-existing project 工程名称”。
在ubuntu中运行eclipse的时候弹出错误,错误内容
我出现此问题的原因是 jdk1.6的版本是64位的 下载的eclipse是32(x86)的所以导致以上错误