cpu占用率高 - 用Java限制线程的CPU/内存使用率?




java cpu占用率高 (6)

我正在编写一个运行多个线程的应用程序,并希望限制这些线程的CPU /内存使用量。

对于C ++也有类似的问题 ,但我想尽可能避免使用C ++和JNI。 我意识到使用更高级别的语言可能无法做到这一点,但我很想知道是否有人有任何想法。

编辑:增加了赏金; 我想要一些非常好的,深思熟虑的想法。

编辑2:我需要的情况是在我的服务器上执行其他人的代码。 基本上它是完全任意的代码,唯一的保证是类文件上会有一个main方法。 目前,在运行时加载的多个完全不同的类作为单独的线程同时执行。

它的编写方式,重构为每个执行的类创建单独的进程将是一件痛苦的事。 如果这是通过VM参数限制内存使用的唯一好方法,那就这样吧。 但我想知道是否有办法用线程来做。 即使作为一个单独的进程,我也希望能够以某种方式限制其CPU使用率,因为正如我之前提到的,其中一些将立即执行。 我不想要一个无限循环来占用所有资源。

编辑3:近似对象大小的简单方法是使用java的Instrumentation类; 特别是getObjectSize方法。 请注意,使用此工具需要一些特殊设置。


Thread.setPriority()可能会有所帮助,但它不允许您限制线程使用的CPU。 事实上,我还没有听说过任何Java库可以做到这一点。

如果您的线程准备合作,则可以实现此类工具。 关键是让线程定期调用自定义调度程序,并让调度程序使用JMX监视线程CPU使用情况。 但问题是,如果某个线程没有经常调度调度程序,它可能会超出限制限制。 对于一个陷入循环的线程,你无能为力。

实施的另一个理论途径是使用Isolates。 不幸的是,您很难找到实现隔离的通用JVM。 此外,标准API仅允许您控制隔离,而不是隔离内的线程。


为什么不进行“线程化”而不进行协作式多任务处理,看看是否可以操作http://www.janino.net/来运行程序一段时间/一组插入,然后停止并运行下一个节目。 至少这种方式公平,给每个人同样的时间片......


如果在单独的进程中运行线程,则可以限制内存使用量并限制CPU数量或更改这些线程的优先级。

但是,您所做的任何事情都可能增加开销和复杂性,而这通常会适得其反。

除非你能解释为什么你会这样做(例如你有一个写得不好的图书馆,你不信任,不能得到支持),我建议你不需要。

它不容易限制内存使用的原因是只有一个共享堆。 因此,在一个线程中使用的对象可以在另一个线程中使用,而不是分配给一个线程或另一个线程。

限制CPU使用率意味着停止所有线程,以便它们不做任何事情,但更好的方法是确保线程不浪费CPU并且只是主动执行需要完成的工作,在这种情况下你不会想阻止他们这样做。


如果我理解你的问题,一种方法是自适应地睡眠线程,就像用Java完成视频播放一样。 如果你知道你想要50%的核心利用率,你的算法应该睡眠大约0.5秒 - 可能在一秒钟内分布(例如0.25秒计算,0.25秒睡眠等)。 这是我视频播放器的一个example

long starttime = 0; // variable declared
//...
// for the first time, remember the timestamp
if (frameCount == 0) {
    starttime = System.currentTimeMillis();
}
// the next timestamp we want to wake up
starttime += (1000.0 / fps);
// Wait until the desired next time arrives using nanosecond
// accuracy timer (wait(time) isn't accurate enough on most platforms) 
LockSupport.parkNanos((long)(Math.max(0, 
    starttime - System.currentTimeMillis()) * 1000000));

此代码将根据帧/秒值休眠。

为了节省内存使用量,您可以将对象创建包装到工厂方法中,并使用某种具有有限许可的信号量作为字节来限制估计的总对象大小(您需要估计各种对象的大小以定义信号量) )。

package concur;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class MemoryLimited {
    private static Semaphore semaphore = new Semaphore(1024 * 1024, true);
    // acquire method to get a size length array
    public static byte[] createArray(int size) throws InterruptedException {
        // ask the semaphore for the amount of memory
        semaphore.acquire(size);
        // if we get here we got the requested memory reserved
        return new byte[size];
    }
    public static void releaseArray(byte[] array) {
        // we don't need the memory of array, release
        semaphore.release(array.length);
    }
    // allocation size, if N > 1M then there will be mutual exclusion
    static final int N = 600000;
    // the test program
    public static void main(String[] args) {
        // create 2 threaded executor for the demonstration
        ExecutorService exec = Executors.newFixedThreadPool(2);
        // what we want to run for allocation testion
        Runnable run = new Runnable() {
            @Override
            public void run() {
                Random rnd = new Random();
                // do it 10 times to be sure we get the desired effect
                for (int i = 0; i < 10; i++) {
                    try {
                        // sleep randomly to achieve thread interleaving
                        TimeUnit.MILLISECONDS.sleep(rnd.nextInt(100) * 10);
                        // ask for N bytes of memory
                        byte[] array = createArray(N);
                        // print current memory occupation log
                        System.out.printf("%s %d: %s (%d)%n",
                            Thread.currentThread().getName(),
                            System.currentTimeMillis(), array,
                            semaphore.availablePermits());
                        // wait some more for the next thread interleaving
                        TimeUnit.MILLISECONDS.sleep(rnd.nextInt(100) * 10);
                        // release memory, no longer needed
                        releaseArray(array);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        // run first task
        exec.submit(run);
        // run second task
        exec.submit(run);
        // let the executor exit when it has finished processing the runnables
        exec.shutdown();
    }
}

您可以通过JMX获得有关CPU和内存使用情况的大量信息,但我认为它不允许任何主动操作。

要在某种程度上控制CPU使用率,可以使用Thread.setPriority()

至于内存,没有每线程内存这样的东西。 Java线程的概念意味着共享内存。 控制内存使用的唯一方法是通过命令行选项(如-Xmx),但无法在运行时操作设置。


要减少CPU,您需要在常见的ifwhile循环中休眠线程。

while(whatever) {
    //do something
    //Note the capitol 'T' here, this sleeps the current thread.
    Thread.sleep(someNumberOfMilliSeconds);
}

休眠几百毫秒将大大降低CPU使用率,几乎没有明显的性能结果。

至于内存,我会在各个线程上运行一个分析器并进行一些性能调整。 如果你限制了线程可用的内存量,我认为可能存在内存不足或缺乏线程的问题。 我相信JVM可以提供与所需线程一样多的内存,并且通过在任何给定时间仅保留范围内的基本对象来减少内存使用。





throttling