2013-08-29 2 views
3

나는 최근까지 작업 한 오래된 코드를 가지고 있지만, 그것은 6.는 파일 기술자를 떠날 것으로 보인다

문제가 보인다 오픈 JDK 6보다는 자바 SE 사용하여 새 서버에서 실행하는 것이 지금 발프 보인다 JAI.create를 중심으로 나는 jpeg 파일을 내가 스케일 및 png 파일을 변환합니다. 이 코드는 누수없이 작동하지만 OpenJDK를 실행하는 상자로 옮겨 졌기 때문에 파일 설명자가 닫히지 않는 것처럼 보입니다. 점점 더 많은 tmp 파일이 서버의 tmp 디렉토리에 누적되는 것을 볼 수 있습니다. 이것들은 내가 만드는 파일이 아니기 때문에 JAI가 그것을하는 것으로 가정합니다.

또 다른 이유는 새 서버에서 더 큰 힙 크기 일 수 있습니다. JAI가 마무리 작업을 정리하지만 GC가 자주 발생하지 않는다면 파일이 쌓일 수 있습니다. 힙 크기를 줄이는 것은 선택 사항이 아니며 증가하는 ulimit와 관련없는 문제가있는 것 같습니다. 여기

내가이 프로그램을 실행할 때 누수 파일의 예 :

/tmp/imageio7201901174018490724.tmp 

일부 코드 :

// Processor is an internal class that aggregates operations 
// performed on the image, like resizing 
private byte[] processImage(Processor processor, InputStream stream) { 
    byte[] bytes = null; 
    SeekableStream s = null; 
    try { 
     // Read the file from the stream 
     s = SeekableStream.wrapInputStream(stream, true); 
     RenderedImage image = JAI.create("stream", s); 
     BufferedImage img = PlanarImage.wrapRenderedImage(image).getAsBufferedImage(); 
     // Process image 
     if (processor != null) { 
      image = processor.process(img); 
     } 
     // Convert to bytes 
     bytes = convertToPngBytes(image); 
    } catch (Exception e){ 
     // error handling 
    } finally { 
     // Clean up streams 
     IOUtils.closeQuietly(stream); 
     IOUtils.closeQuietly(s); 
    } 
    return bytes; 
} 

private static byte[] convertToPngBytes(RenderedImage image) throws IOException { 
    ByteArrayOutputStream out = null; 
    byte[] bytes = null; 
    try { 
     out = new ByteArrayOutputStream(); 
     ImageIO.write(image, "png", out); 
     bytes = out.toByteArray(); 
    } finally { 
     IOUtils.closeQuietly(out); 
    } 
    return bytes; 
} 

내 질문

은 다음과 같습니다

  1. 사람이로 실행하고 그것을 해결 했습니까? 생성 된 tmp 파일은 내 것이 아니기 때문에, 나는 그들의 이름이 무엇인지 모르기 때문에 그들에 관해서는 아무 것도 할 수 없다.
  2. 이미지 크기를 조정하고 이미지를 다시 포맷 할 때 선택하는 라이브러리는 무엇입니까? 나는 Scalr에 대해 들었다.

차라리이 시간에 이전 코드를 rewite 아닌 것 다른 선택의 여지가없는 경우 ...

감사합니다!

답변

0

발견!

그래서 스트림은 코드의 다른 지역에서 다른 스트림에 의해 포장됩니다 :

iis = ImageIO.createImageInputStream(stream); 

그리고 더 아래는, 스트림이 닫혀 있습니다.

Sun Java로 실행할 때 리소스가 누출되지 않지만 Open JDK를 실행할 때 누수가 발생할 수 있습니다.

내가 왜 추측 할 수 있겠지만 (나는 추측 할 수 있지만 소스 코드를 확인하지는 못했지만) 그 이유는 확실하지 않습니다. 일단 래핑 스트림을 명시 적으로 닫으면 모든 것이 잘되었습니다.

+0

그래서이 경우에는'iis.close()'를 명시 적으로 호출했는데 문제가 해결 되었습니까? – rogerdpack

+0

@rogerdpack 아아, 오래 전이었고, 내가 한 일을 떠 올릴 수 없습니다. 나는 대답이 암시하는 것 같아, 나는 그것이 실제로 내가 한 일인지 확인할 수 없다. 죄송합니다. – MrSilverSnorkel

4

임시 파일/종료 자 문제에 대한 의견 만 남았습니다. 문제의 근원을 해결 한 것 같습니다 (주석이 너무 길기 때문에 답변으로 게시 할 예정입니다 ... :-P) :

임시 파일은 ImageIO의 FileCacheImageInputStream에 의해 생성됩니다. 이러한 인스턴스는 ImageIO.createImageInputStream(stream)을 호출 할 때마다 생성되며 useCache 플래그는 true (기본값)입니다. 메모리 캐싱을 희생시키면서 디스크 캐싱을 사용하지 않으려면 false으로 설정할 수 있습니다. 이것은 큰 힙을 가지고있는 것처럼 의미가있을 수 있지만 매우 큰 이미지를 처리하는 중이 아닐 수도 있습니다.

파이널 라이저 문제에 대해 (거의) 맞다고 생각합니다.당신은 FileCacheImageInputStream에서 다음 'finalize' 방법을 찾을 수 있습니다 (일 JDK 6/1.6.0_26) :

이 클래스의 생성자에서 몇 가지 매우 "흥미로운"코드가있다
protected void finalize() throws Throwable { 
    // Empty finalizer: for performance reasons we instead use the 
    // Disposer mechanism for ensuring that the underlying 
    // RandomAccessFile is closed/deleted prior to garbage collection 
} 

, 자동 스트림 폐쇄와 폐기를 설정 인스턴스가 완료 될 때 (클라이언트 코드가 그렇게하지 않아야하는지). 이것은 OpenJDK의 암시에서 다를 수 있습니다. 적어도 해커처럼 보입니다. 그것은

어떤 경우

, 당신이 지금처럼 제대로 파일 기술자를 닫고 것이라고 ImageInputStream 인스턴스에서 close를 호출하는 것 같다 ... "성능상의 이유로는"우리가 얘기 정확히 어떤 순간에 나에게도 불분명 임시 파일을 삭제하십시오.

+0

입력 해 주셔서 감사합니다. 나는 소스 코드를 파고 들지 않았다는 것을 인정한다. 나는 또한 캐시 설정을 인식하지 못했습니다. 많은 호평을 받았습니다. – MrSilverSnorkel

+0

바로 당신이 ... 완료되었습니다. – MrSilverSnorkel

+1

확실히 이상한 일이 벌어지고 있습니다. JNA는 핸들을 너무 일찍 닫고있었습니다. 이상한 http://stackoverflow.com/q/38444752/32453 – rogerdpack

관련 문제