首页 > 解决方案 > 如何使用 -XX:OnOutOfMemoryError= 在 OOM 执行脚本

问题描述

我正在尝试设置一种方法来处理我的应用程序中的内存不足错误。到目前为止,我已将以下选项添加到我的 Gradle 构建文件中:

task appStartScripts(type: CreateStartScripts) {
    def tplName = 'startTemplate.sh'
    assert project.file(tplName).exists()
    defaultJvmOpts = ["-XX:+HeapDumpOnOutOfMemoryError",
                      "-XX:HeapDumpPath=\$HOME/log/",
                      "-XX:OnOutOfMemoryError=./\$HOME/application/bin/restart.sh",
                      "-Xms64m", "-Xmx124m"]
    dependsOn shadowJar
    applicationName = 'start'
    defaultJvmOpts += ["-Dspring.profiles.active=ENV_VARIABLE"]
    classpath = startShadowScripts.classpath
    mainClassName = startShadowScripts.mainClassName
    outputDir = new File(project.buildDir, 'scriptsShadow')

    doLast {
        // IMPORTANT! needed to ensure HOME environment variable is expanded correctly
        unixScript.text = unixScript.text.replace('\\$HOME', '\'"$HOME"\'')
        unixScript.text = unixScript.text.replace('ENV_VARIABLE', '\'"$1"\'')
}

其中 XX:OnOutOfMemoryError 在发生内存不足错误时调用重启脚本。在 restart.sh 脚本本身中,我有以下内容:

while true : do
    java -XX:+ExitOnOutOfMemoryError -jar application.jar
    sleep 5
done

./start.sh

要杀死应用程序,请等待 5 秒,然后在同一目录中调用启动脚本以重新启动应用程序。

为了测试这一点,我在我的一个 get 请求中添加了一个无限循环:

@GET
    @Timed
    @Path("/{ids}")
    public List<Profile> getProfileByID(@PathParam("ids") String ids) {

        boolean forever = true;

        try {
            logger.info("STARTED SERVICE: getProfileID with the following parameters: IDs = {}", ids);
            int[] array = idsStringToArray(ids);

            List<Profile> profileList = profileManager.getProfiles(array);

            List<Integer> myList = new ArrayList<Integer>();

            while (forever) {
                profileManager.getProfiles(array);
                myList.add(1000);
            }

            logger.info("COMPLETED SERVICE: getProfileID with the following parameters: Ids = {}", ids);
            return profileList;
        }

myList 将继续向其中添加更多项目,从而消耗内存。

也就是说,我还不能导致错误触发脚本。还有什么我可以做的吗?

此外,这是该服务的 top 命令的结果:

Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
%Cpu(s):  1.4 us,  1.3 sy,  0.0 ni, 97.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 32160180 total, 21291040 free,  4559124 used,  6310016 buff/cache
KiB Swap:  2097148 total,  2097148 free,        0 used. 27127132 avail Mem
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
30504 user1  20   0 3778748 371724  18048 S   4.0  1.2   3:50.33 java

编辑:我只是尝试直接在代码中调用 OOM 错误,但它只是抛出异常而没有别的:

@GET
    @Timed
    @Path("/{ids}")
    public List<Profile> getProfileByID(@PathParam("ids") String ids) {

        boolean forever = true;

        try {
            logger.info("STARTED SERVICE: getProfileID with the following parameters: IDs = {}", ids);
            int[] array = idsStringToArray(ids);

            List<Profile> profileList = profileManager.getProfiles(array);

            throw new OutOfMemoryError();
        }

标签: javatestingerror-handlingjvmout-of-memory

解决方案


我能够引发错误。我通过比以前更多地降低堆空间来做到这一点:

"-Xms64m", "-Xmx124m",

并通过让我的 get 方法生成一个 long 数组 l:

@GET
@Timed
@Path("/{ids}")
public List<Profile> getProfileByID(@PathParam("ids") String ids) {

    boolean forever = true;

    try {
        logger.info("STARTED SERVICE: getProfileID with the following parameters: IDs = {}", ids);
        int[] array = idsStringToArray(ids);

        List<Profile> profileList = profileManager.getProfiles(array);

        long[] l = new long[Integer.MAX_VALUE];


推荐阅读