문제

저는 여러 스레드가 실행되는 애플리케이션을 작성 중이며 해당 스레드의 CPU/메모리 사용량을 제한하려고 합니다.

이있다 C++에 대한 비슷한 질문, 하지만 가능하다면 C++와 JNI를 사용하지 않으려고 합니다.더 높은 수준의 언어를 사용하면 이것이 불가능할 수도 있다는 것을 알고 있지만 누군가 아이디어가 있는지 궁금합니다.

편집하다: 현상금이 추가되었습니다.나는 이것에 대해 정말 훌륭하고 잘 생각된 아이디어를 원합니다.

편집 2: 이것이 필요한 상황은 내 서버에서 다른 사람의 코드를 실행하는 것입니다.기본적으로 이는 완전히 임의의 코드이며 클래스 파일에 기본 메서드가 있다는 것만 보장됩니다.현재 런타임 시 로드되는 완전히 다른 여러 클래스가 별도의 스레드로 동시에 실행되고 있습니다.

작성된 방식에 따르면, 실행되는 각 클래스에 대해 별도의 프로세스를 생성하기 위해 리팩토링하는 것은 어려울 것입니다.이것이 VM 인수를 통해 메모리 사용량을 제한하는 유일한 좋은 방법이라면 그렇게 하십시오.하지만 스레드를 사용하여 이를 수행할 수 있는 방법이 있는지 알고 싶습니다.별도의 프로세스이더라도 앞서 언급한 것처럼 여러 프로세스가 동시에 실행되므로 CPU 사용량을 어떻게든 제한할 수 있기를 바랍니다.나는 모든 리소스를 소모하는 무한 루프를 원하지 않습니다.

편집 3: 객체 크기를 대략적으로 계산하는 쉬운 방법은 Java를 사용하는 것입니다. 수단 클래스;특히 getObjectSize 메소드입니다.이 도구를 사용하려면 몇 가지 특별한 설정이 필요합니다.

도움이 되었습니까?

해결책

내가 당신의 문제를 이해한다면, 한 가지 방법은 비디오 재생이 Java에서 수행되는 것과 마찬가지로 스레드를 적응 적으로자는 것입니다. 50% 코어 활용을 원한다면 알고리즘은 약 0.5 초 동안 잠을 자야합니다 (예 : 0.25 초 계산, 0.25 초 수면 등). 여기에 있습니다 예시 내 비디오 플레이어에서.

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();
    }
}

다른 팁

다음을 통해 CPU 및 메모리 사용량에 대한 많은 정보를 얻을 수 있습니다. JMX, 하지만 적극적인 조작을 허용하지는 않는다고 생각합니다.

CPU 사용량을 어느 정도 제어하려면 다음을 사용할 수 있습니다. Thread.set우선순위().

메모리의 경우 스레드별 메모리 같은 것이 없습니다.Java 스레드의 개념 자체가 공유 메모리를 의미합니다.메모리 사용량을 제어하는 ​​유일한 방법은 -Xmx와 같은 명령줄 옵션을 사용하는 것이지만 런타임에 설정을 조작할 수 있는 방법은 없습니다.

돌보는 자바 포럼. 기본적으로 실행시기를 한 다음 너무 많은 시간이 걸릴 때 대기합니다. 원래 스레드에서 언급 된 바와 같이, 이것을 별도의 스레드로 실행하고 작업 스레드를 방해하면 시간이 지남에 따라 평균 값을 평균화 할 수 있으므로보다 정확한 결과를 얻을 수 있습니다.

import java.lang.management.*;

ThreadMXBean TMB = ManagementFactory.getThreadMXBean();
long time = new Date().getTime() * 1000000;
long cput = 0;
double cpuperc = -1;

while(true){

if( TMB.isThreadCpuTimeSupported() ){
    if(new Date().getTime() * 1000000 - time > 1000000000){ //Reset once per second
        time = new Date().getTime() * 1000000;
        cput = TMB.getCurrentThreadCpuTime();
    }

    if(!TMB.isThreadCpuTimeEnabled()){
        TMB.setThreadCpuTimeEnabled(true);
    }

    if(new Date().getTime() * 1000000 - time != 0)
        cpuperc = (TMB.getCurrentThreadCpuTime() - cput) / (new Date().getTime() *  1000000.0 - time) * 100.0;                  
    }
//If cpu usage is greater then 50%
if(cpuperc > 50.0){
     //sleep for a little bit.
     continue;
}
//Do cpu intensive stuff
}

가장 관련성이 높은 스레드가 더 자주 예약되도록 스레드에 다른 우선 순위를 할당 할 수 있습니다.

이거 봐요 대답 그것이 도움이되는지 확인합니다.

모든 실행 스레드가 우선 순위가 동일하면 다음과 같이 실행될 수 있습니다.

t1, t2, t3,     t1, t2, t3,   t1, t2, t3

그들 중 하나에 다른 우선 순위를 할당하면 다음과 같이 보일 수 있습니다.

t1, t1, t1, t1,    t2,    t1, t1, t1 t3.

즉, 첫 번째 스레드가 나머지는 "더 자주"실행됩니다.

별도의 프로세스에서 스레드를 실행하면 메모리 사용량을 제한하고 CPU 수를 제한하거나 이러한 스레드의 우선 순위를 변경할 수 있습니다.

그러나 당신이하는 일은 종종 비생산적인 오버 헤드와 복잡성을 추가 할 가능성이 높습니다.

왜이 일을하고 싶은지 설명 할 수 없다면 (예 : 신뢰할 수없고 지원할 수없는 잘못 쓰여진 도서관이 있습니다) 나는 당신이 필요하지 않을 것을 제안 할 것입니다.

메모리 사용을 제한하기 쉽지 않은 이유는 공유 된 힙만이 하나만 있기 때문입니다. 따라서 한 스레드에서 사용되는 객체는 다른 스레드에서 사용할 수 있으며 한 스레드 또는 다른 스레드에 할당되지 않습니다.

CPU 사용을 제한한다는 것은 모든 스레드를 중지하여 아무것도하지 않도록하는 것을 의미하지만 더 나은 접근 방식은 스레드가 CPU를 낭비하지 않고 수행 해야하는 작업 만 수행하는 것입니다. 그들이하는 것을 멈추고 싶다.

"스레딩"을하는 대신 협력 멀티 태스킹을하는 대신 왜 조작 할 수 있는지 보는 것이 흥미로울 것입니다. http://www.janino.net/ 일정 시간/intstructions 세트 동안 프로그램을 실행하려면 다음 프로그램을 중지하고 실행하십시오. 적어도 그렇게 공정하게, 모든 사람에게 동시에 슬라이스를 줘 ...

Thread.setPriority ()는 도움이 될 수 있지만 스레드에서 사용하는 CPU를 캡처 할 수는 없습니다. 사실, 나는 이것을하는 Java 라이브러리에 대해 들어 본 적이 없습니다.

스레드가 협력 할 준비가되어 있으면 이러한 시설을 구현할 수 있습니다. 키는 스레드가 정기적으로 사용자 정의 스케줄러로 호출하고 JMX를 사용하여 스케줄러 모니터 스레드 CPU 사용을하도록하는 것입니다. 그러나 문제는 일부 스레드가 스케줄러 호출을 충분히 충분히 만들지 않으면 스로틀링 한계를 초과 할 수 있다는 것입니다. 그리고 루프에 갇히는 스레드에 대해 할 수있는 일은 없습니다.

구현하는 또 다른 이론적 경로는 분리 물을 사용하는 것입니다. 불행히도, 당신은 격리를 구현하는 범용 JVM을 찾기가 어려울 것입니다. 게다가, 표준 API를 사용하면 분리 물 내의 스레드가 아니라 분리 물을 제어 할 수 있습니다.

스레드 CPU 사용을 제한 할 수있는 유일한 방법은 리소스의 블록 또는 수율 ()를 자주 호출하는 것입니다.

이것은 CPU 사용을 100% 미만으로 제한하지 않지만 다른 스레드와 프로세스 더 많은 시간 경과를 제공합니다.

CPU를 줄이려면 Common 내부의 실을 잠들고 싶습니다. 만약에 그리고 동안 루프.

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

수백 밀리 초 동안 자면 성능에 대한 눈에 띄는 결과가 거의 없거나 전혀없는 CPU 사용량을 크게 줄입니다.

메모리는 개별 스레드에서 프로파일 러를 실행하고 성능 튜닝을 수행합니다. 스레드에 사용할 수있는 메모리의 양을 조절하면 메모리 외 예외 또는 굶주린 스레드가있을 가능성이 높습니다. 나는 JVM이 필요한 스레드만큼 많은 메모리를 제공한다고 믿고 주어진 시간에 필수 객체 만 범위를 유지함으로써 메모리 사용을 줄이기 위해 노력할 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top