Loading

CPU和Memory压测程序

背景:服务暂未上线,但是为了避免缩容,需要有一个程序提高服务器CPU和Memory使用率.

代码实现

创建maven工程,编写主实现类。
App.java

package org.example;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * CPU和内存测试工具
 */
public class App {
    private static final int DEFAULT_THREADS = Runtime.getRuntime().availableProcessors();
    private static final int DEFAULT_DURATION = -1; // 默认无限运行,直到用户中断
    private static final int DEFAULT_MEMORY = 0; // 默认不占用额外内存

    public static void main(String[] args) {
        int threads = DEFAULT_THREADS;
        int duration = DEFAULT_DURATION;
        int memoryMB = DEFAULT_MEMORY;
        boolean cpuTest = true; // 默认进行CPU测试
        boolean memoryTest = false;

        // 解析命令行参数
        for (int i = 0; i < args.length; i++) {
            if ("-t".equals(args[i]) && i + 1 < args.length) {
                try {
                    threads = Integer.parseInt(args[i + 1]);
                    i++;
                } catch (NumberFormatException e) {
                    System.err.println("线程数必须是整数");
                    printUsage();
                    System.exit(1);
                }
            } else if ("-d".equals(args[i]) && i + 1 < args.length) {
                try {
                    duration = Integer.parseInt(args[i + 1]);
                    i++;
                } catch (NumberFormatException e) {
                    System.err.println("持续时间必须是整数(秒)");
                    printUsage();
                    System.exit(1);
                }
            } else if ("-m".equals(args[i]) && i + 1 < args.length) {
                try {
                    memoryMB = Integer.parseInt(args[i + 1]);
                    memoryTest = true;
                    i++;
                } catch (NumberFormatException e) {
                    System.err.println("内存量必须是整数(MB)");
                    printUsage();
                    System.exit(1);
                }
            } else if ("--no-cpu".equals(args[i])) {
                cpuTest = false;
            } else if ("-h".equals(args[i]) || "--help".equals(args[i])) {
                printUsage();
                System.exit(0);
            }
        }

        System.out.println("开始性能压力测试");

        // 显示测试配置
        if (cpuTest) {
            System.out.println("CPU测试线程数: " + threads);
        }

        if (memoryTest) {
            System.out.println("内存占用: " + memoryMB + " MB");
        }

        if (duration > 0) {
            System.out.println("持续时间: " + duration + " 秒");
        } else {
            System.out.println("持续时间: 无限制(按Ctrl+C终止)");
        }

        // 启动测试
        runStressTest(cpuTest, memoryTest, threads, memoryMB, duration);
    }

    private static void printUsage() {
        System.out.println("用法: java -jar cpu-service.jar [选项]");
        System.out.println("选项:");
        System.out.println("  -t <数值>    设置线程数 (默认: 可用处理器数量)");
        System.out.println("  -d <数值>    设置持续时间,单位秒 (默认: 无限制运行,需手动中断)");
        System.out.println("  -m <数值>    设置内存占用量,单位MB (默认: 0, 不进行内存测试)");
        System.out.println("  --no-cpu     不执行CPU测试 (默认: 执行CPU测试)");
        System.out.println("  -h, --help   显示帮助信息");
        System.out.println("\n可同时进行CPU和内存测试,例如:");
        System.out.println("  java -jar cpu-service.jar -t 4 -m 1024 -d 60");
    }

    /**
     * 运行压力测试(可同时进行CPU和内存测试)
     * @param cpuTest 是否进行CPU测试
     * @param memoryTest 是否进行内存测试
     * @param threads CPU测试线程数
     * @param memoryMB 内存占用量(MB)
     * @param durationSeconds 持续时间(秒),-1表示无限运行
     */
    private static void runStressTest(boolean cpuTest, boolean memoryTest, int threads, int memoryMB, int durationSeconds) {
        ExecutorService executor;
        List<CpuLoadTask> cpuTasks = new ArrayList<>();
        MemoryLoadTask memoryTask;
        Thread memoryThread;

        // 启动CPU测试
        if (cpuTest) {
            System.out.println("启动CPU压力测试...");
            executor = Executors.newCachedThreadPool();

            // 创建并启动CPU任务
            for (int i = 0; i < threads; i++) {
                CpuLoadTask task = new CpuLoadTask();
                cpuTasks.add(task);
                executor.submit(task);
            }
        } else {
            executor = null;
        }

        // 启动内存测试
        if (memoryTest) {
            System.out.println("启动内存压力测试...");
            memoryTask = new MemoryLoadTask(memoryMB);
            memoryThread = new Thread(memoryTask);
            memoryThread.start();
        } else {
            memoryTask = null;
            memoryThread = null;
        }


        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.out.println("\n正在停止压力测试...");

            // 停止CPU测试
            if (cpuTest) {
                for (CpuLoadTask task : cpuTasks) {
                    task.stop();
                }
                if (executor != null) {
                    executor.shutdown();
                    try {
                        if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
                            executor.shutdownNow();
                        }
                    } catch (InterruptedException e) {
                        executor.shutdownNow();
                    }
                }
                System.out.println("CPU压力测试已停止");
            }

            // 停止内存测试
            if (memoryTest && memoryTask != null) {
                memoryTask.stop();
                System.out.println("内存压力测试已停止");
            }
        }));

        // 每3秒打印一次系统状态
        Thread monitorThread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    Thread.sleep(3000);

                    // 打印内存使用情况
                    if (memoryTest) {
                        long totalMemory = Runtime.getRuntime().totalMemory() / (1024 * 1024);
                        long freeMemory = Runtime.getRuntime().freeMemory() / (1024 * 1024);
                        long usedMemory = totalMemory - freeMemory;
//                        System.out.println("当前内存使用: " + usedMemory + "MB / " + totalMemory + "MB");
                    }

                    // 这里可以添加CPU使用率监控
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        });
        monitorThread.setDaemon(true);
        monitorThread.start();

        if (durationSeconds > 0) {
            // 运行指定的时间
            try {
                Thread.sleep(durationSeconds * 1000L);

                // 停止所有任务
                if (cpuTest) {
                    for (CpuLoadTask task : cpuTasks) {
                        task.stop();
                    }

                    if (executor != null) {
                        executor.shutdown();
                        try {
                            if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
                                executor.shutdownNow();
                            }
                        } catch (InterruptedException e) {
                            executor.shutdownNow();
                            Thread.currentThread().interrupt();
                        }
                    }
                }

                if (memoryTest && memoryTask != null) {
                    memoryTask.stop();
                }

                monitorThread.interrupt();
                System.out.println("压力测试完成");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        } else {
            // 无限运行,等待用户中断
            try {
                // 等待任意活动线程结束(实际上不会结束,除非用户中断)
                if (memoryThread != null) {
                    memoryThread.join();
                } else {
                    Thread.currentThread().join();
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    /**
     * 内存负载任务
     */
    private static class MemoryLoadTask implements Runnable {
        private volatile boolean running = true;
        private final int targetMemoryMB;
        private static final List<byte[]> memoryBlocks = new ArrayList<>();

        public MemoryLoadTask(int memoryMB) {
            this.targetMemoryMB = memoryMB;
        }

        @Override
        public void run() {
            try {
                // 分配指定大小的内存
                allocateMemory();

                // 保持程序运行并保持内存分配状态
                while (running) {
                    // 每个内存块执行一些操作,确保它们不会被GC回收
                    touchMemoryBlocks();
                    Thread.sleep(1000);
                }
            } catch (OutOfMemoryError e) {
                System.err.println("内存分配失败,请尝试较小的内存值: " + e.getMessage());
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                // 释放内存
                memoryBlocks.clear();
                System.gc();
            }
        }

        private void allocateMemory() {
            int allocated = 0;
            // 每次分配1MB块
            final int blockSize = 1024 * 1024; // 1MB

            while (allocated < targetMemoryMB && running) {
                try {
                    memoryBlocks.add(new byte[blockSize]);
                    allocated++;
                } catch (OutOfMemoryError e) {
                    System.err.println("在分配 " + allocated + "MB 后内存不足");
                    break;
                }
            }

            System.out.println("内存分配完成,共分配 " + allocated + "MB");
        }

        private void touchMemoryBlocks() {
            // 随机访问内存块,确保它们不被GC回收
            if (!memoryBlocks.isEmpty()) {
                int randomIndex = (int) (Math.random() * memoryBlocks.size());
                byte[] block = memoryBlocks.get(randomIndex);
                if (block != null && block.length > 0) {
                    // 写入一些数据
                    block[0] = 1;
                    // 读取一些数据
                    byte temp = block[block.length / 2];
                    // 确保使用了读取的值
                    if (temp == Byte.MAX_VALUE) {
                        block[0] = 0;
                    }
                }
            }
        }

        public void stop() {
            running = false;
            memoryBlocks.clear();
            System.gc();
        }
    }

    /**
     * CPU负载任务
     */
    private static class CpuLoadTask implements Runnable {
        private volatile boolean running = true;
        private static final int LOOP_COUNT = 10000;
        private static final int INNER_LOOP_COUNT = 1000;

        @Override
        public void run() {
            // 使用原始数组而不是Java集合,以避免GC和优化
            double[] results = new double[4096];
            long[] primeNumbers = new long[1024];

            // 设置线程优先级为最高,确保获得最大CPU时间
            Thread.currentThread().setPriority(Thread.MAX_PRIORITY);

            // 预填充素数数组,避免初始化开销
            generatePrimeNumbers(primeNumbers);

            while (running) {
                try {
                    // 使用多种不同类型的计算来消耗CPU
                    for (int i = 0; i < LOOP_COUNT; i++) {
                        // 1. 浮点数密集型计算
                        doFloatingPointCalculations(results);

                        // 2. 整数密集型计算
                        doIntegerCalculations(primeNumbers);

                        // 3. 位操作密集型计算
                        doBitwiseOperations(results);

                        // 4. 混合计算
                        doMixedCalculations(results, primeNumbers);
                    }

                    // 强制使用计算结果,防止编译器优化掉计算
                    double sum = 0;
                    for (double result : results) {
                        sum += result;
                    }

                    // 使用volatile变量存储结果,确保不被优化掉
                    if (sum == Double.POSITIVE_INFINITY) {
                        System.out.println(".");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        /**
         * 生成素数填充数组
         */
        private void generatePrimeNumbers(long[] primes) {
            int count = 0;
            long num = 2;
            while (count < primes.length) {
                if (isPrime(num)) {
                    primes[count++] = num;
                }
                num++;
            }
        }

        /**
         * 检查一个数是否为素数
         */
        private boolean isPrime(long n) {
            if (n <= 1) return false;
            if (n <= 3) return true;
            if (n % 2 == 0 || n % 3 == 0) return false;

            for (long i = 5; i * i <= n; i += 6) {
                if (n % i == 0 || n % (i + 2) == 0) return false;
            }
            return true;
        }

        /**
         * 执行浮点数密集型计算
         */
        private void doFloatingPointCalculations(double[] results) {
            for (int i = 0; i < INNER_LOOP_COUNT; i++) {
                int index = i % results.length;
                double a = Math.random() * 100;
                results[index] = Math.sin(a) * Math.cos(a) / (Math.tan(a) + 0.1);
                results[(index + 1) % results.length] = Math.exp(Math.min(a, 3)) * Math.log(a + 1);
                results[(index + 2) % results.length] = Math.pow(a, Math.min(a % 5, 3)) * Math.sqrt(a);
            }
        }

        /**
         * 执行整数密集型计算
         */
        private void doIntegerCalculations(long[] primes) {
            long result = 0;
            for (int i = 0; i < INNER_LOOP_COUNT; i++) {
                int index1 = i % primes.length;
                int index2 = (i * 7 + 3) % primes.length;
                result += (primes[index1] * primes[index2]) % (primes[(index1 + index2) % primes.length] + 1);
            }

            // 确保结果被使用
            if (result == Long.MAX_VALUE) {
                primes[0] = result;
            }
        }

        /**
         * 执行位操作密集型计算
         */
        private void doBitwiseOperations(double[] results) {
            long bits = 0x7FFFFFFFFFFFFFFFL;
            for (int i = 0; i < INNER_LOOP_COUNT; i++) {
                int index = i % results.length;
                bits = (bits << 1) | (bits >>> 63);
                bits ^= (long) results[index];
                bits = Long.rotateLeft(bits, 5);
                bits &= ~(1L << (i % 64));
                results[index] = Double.longBitsToDouble(bits & 0x7FFFFFFFFFFFFFFFL);
            }
        }

        /**
         * 执行混合计算
         */
        private void doMixedCalculations(double[] results, long[] primes) {
            for (int i = 0; i < INNER_LOOP_COUNT; i++) {
                int index1 = i % results.length;
                int index2 = i % primes.length;

                // 混合浮点计算和整数计算
                double value = Math.sin(results[index1]) + Math.cos(primes[index2]);
                results[index1] = value * value;

                // 确保每次迭代结果依赖于前一次计算结果
                if (i > 0) {
                    results[index1] += results[(index1 - 1) % results.length] * 0.01;
                }
            }
        }

        public void stop() {
            running = false;
        }
    }
}

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>cpu-service</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>cpu-service</name>
  <description>CPU压力测试工具</description>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <finalName>cpu-service</finalName>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.10.1</version>
        <configuration>
          <source>17</source>
          <target>17</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>3.2.2</version>
        <configuration>
          <archive>
            <manifest>
              <addClasspath>true</addClasspath>
              <mainClass>org.example.App</mainClass>
            </manifest>
          </archive>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.3.0</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <createDependencyReducedPom>false</createDependencyReducedPom>
              <transformers>
                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                  <mainClass>org.example.App</mainClass>
                </transformer>
              </transformers>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

posted @ 2025-04-10 16:10  IamHzc  阅读(42)  评论(0)    收藏  举报