2017-12-04 1 views
1

다소 긴 (48 자) 태그 이름을 가진 큰 (1.7mb) XML 페이로드를 사용하여 Jaxb2를 사용하는 객체에 XML을 언 마샬링하는 데 드는 시간 비용을 측정했습니다. 샘플링 모드에서 실행중인 JProfiler를 통해 스트링 인터네킹 작업은 소비 된 시간의 견고한 부분이었다.Jaxb2에서 문자열 interning을 비활성화하면 Fastinfoset 스트림에서 언 마샬링 속도가 향상됩니다. 비활성화하는 것이 왜 그렇게 어려운가요?

나는 약간의 조사를했고 Jaxb는 인턴 문자열이 아닌 모드에서 실행될 수 있음을 발견했다. 내 이론에 따르면 언 마샬링 중에 문자열을 인터링팅하지 않는 것이 인터 럽션 프로세스 중에 모든 태그 이름 문자열을 해시 할 필요가 없기 때문에 더 많은 힙 메모리를 사용하는 대신 성능을 향상시킬 수 있다는 이론이 있습니다.

Jaxb의 interning 동작을 억제하는 데 사용 된 방법은 Fastinfoset "StAXDocumentParser"(XMLStreamReader를 구현)에서 "org.codehaus.stax2.internNames"및 "org.codehaus.stax2.internNsUris"속성을 설정하는 것이 었습니다. Jaxb가 문자열을 인 텐트화하지 못하게하기 위해 왜 이것을 "true"로 설정해야하는지는 100 % 명확하지 않습니다.하지만 그것이 작동하는 방법입니다.

이들의 JUnit 기반 테스트는 내가 JAXB의 문자열 인턴 행동을하지 않도록하는 것은 큰 성능 차이가 있다는 결론을 사용 무엇 :

https://github.com/gjd6640/fastinfoset-performance-evaluation

그래서 제 질문은 여러 부분입니다 :

1) 중요한 것을 오해하고 Jaxb의 문자열 인턴 행동을 비활성화하려고해서는 안됩니까?

2) Jaxb를 인턴 문자열에 연결하는 더 좋은 방법이 있습니까? "StAXManager"클래스는 이러한 Woodstox 지향 속성을 설정할 수 없습니다. 이 테스트를 위해 나는 아래 보이는 StAXManager를 확장하여 문제를 해킹했다. 이것은 내가 생산에서 사용하지 않으려는 해킹입니다. Jaxb가 Woodstox 스트림에서 언 마샬링 할 때 Woodstox가 이미 인턴쉽을하고 있는지, 그리고 "예"Jaxb가 해당 프로세스 단계를 사용 중지하여 반응하는지 확인합니다. 나는 Jaxb 라이브러리에서 그 논리를 피기 백으로 치고있다. 그래서 이것에 대해 더 좋은 방법을 원한다.

package com.sun.xml.fastinfoset.stax; 
public class JaxbStringInternSuppressionStaxManager extends StAXManager { 
    public JaxbStringInternSuppressionStaxManager() { 
     // Add to the allowable list of feature names so that the user may set these "StAXInputFactory" properties 
     super.features.put("org.codehaus.stax2.internNames", null); 
     super.features.put("org.codehaus.stax2.internNsUris", null); 
    } 
} 

업데이트 : 평소처럼

, "잘 넣어 질문은 반 대답한다." "com.sun.xml.internal.bind.v2.runtime.unmarshaller.StAXStreamConnector"클래스가 "com.sun.xml"클래스인지 확인합니다. .fastinfoset.stax.StAXDocumentParser "는 사용중인 XMLStreamReader에서 할당 가능하며 문자열 인 에이블을 허용하지 않는 경우 내 경우에는 내 스트림 객체가 "com.sun.xml.fastinfoset.stax.StAXDocumentParser"이므로 인턴쉽이 비활성화되지 않습니다. 이제 질문은 "Fastinfoset 라이브러리의 내부 맛을 위해서만이 작업을 수행하는 이유는 무엇입니까?" 어쩌면 신중하게 this post을 읽음으로써 답을 찾을 수있을 것입니다.

또한 적극적인 개발자 사용자 그룹과 같은 질문에 대한 더 나은 포럼이 있다면 해당 정보를 공유하십시오. 그러면이 사람들에게이 게시물을 링크하여 적절한 사람에게이 질문이 표시 될 것입니다.

+0

부록 : Oracle의 "com.sun.xml.bind : jaxb-impl"라이브러리 버전 "2.1-b02-fcs"의 클래스를 묶는 것처럼 보이는 JDK : 64 비트 jdk1.8.0_121을 사용하고 있습니다. –

답변

1

실제 유스 케이스를 사용하지 않고 실제 유스 케이스를 측정하지 않고 프로파일 러나 테스트를 신뢰하지 않으므로 다소 회의적입니다. 그러나 인턴과 관련된 몇 가지 문제가 있습니다. 특히 고정 크기의 풀 크기를 사용하므로 풀이 가득 차면 해시 조회에 대한 일정한 성능이 저하되어 링크 된 목록을 검색합니다. 더 자세한 설명은 http://java-performance.info/string-intern-in-java-6-7-8/을 참조하십시오.

간단히 말해서 풀 크기를 -XX:StringTableSize=n (여기서 n은 이상적으로 소수이어야 함)으로 변경하고 어떤 일이 발생하는지 확인할 수 있습니다.

-XX:+PrintStringTableStatistics을 사용하면 프로그램이 종료되고 다른 크기로 시도 할 때 풀이 어떻게 사용되었는지 확인할 수 있습니다.

편집 : 이것은 "더 좋은 방법이 있습니까?"(즉, 인턴을 더 빠르게하는) 대답이었습니다. 다른 질문은 더 자격이있는 사람에게 맡깁니다.

+0

이것은 매혹적인 일입니다. 정보 주셔서 감사합니다. 간단히 StringTableSize를 약 2 배 증가시킨 다음 약 100 배 증가 시키려고 시도했지만 조금도 개선되지 않았습니다. 내가보고있는 통계에 따르면 내 테스트는 JVM의 기본 해시 맵 크기 인 60k 만 3090을 사용하는 것처럼 보입니다. StringTable 통계 : 버킷 수 : 60013 = 480104 바이트, 평균값 8.000 항목 수 : 3090 = 74160 바이트, 평균 24.000 리터럴 수 : 3090 = 256072 바이트, 평균 82.871 총 풋 프린트 : = 810336 바이트 –

0

해결 옵션 1 : 간단한 방법이 Fastinfoset 라이브러리와 더 나은 수행 JAXB의 버전을 사용하는 다른 JAXB 구현 JAXB-IMPL에서

풀에 전체 응용 프로그램을 통해 스왑 :

<!-- Both of these libs must be here in order to get performant behavior out of Jaxb by default. 
--> 
<dependency> 
     <groupId>com.sun.xml.fastinfoset</groupId> 
     <artifactId>FastInfoset</artifactId> 
     <version>1.2.13</version> 
     <scope>compile</scope> 
</dependency> 
<dependency> <!-- This artifactId also exists under javax.xml.bind but it appears that nobody uses that one... --> 
    <groupId>javax.xml</groupId> 
    <artifactId>jaxb-impl</artifactId> 
    <version>2.1</version> 
    <scope>runtime</scope> 
</dependency> 
<!-- End: Both of these libs... --> 

이것은 나머지 코드에서 사용되는 jaxb 버전을 업데이트하는 부작용이 있습니다. 어떤 경우에는 바람직하지 않을 수 있습니다. 예를 들어 다양한 앱에서 사용할 수 있어야하는 공유 라이브러리를 만드는 경우 공유 구성 요소를 가져올 때이 기능을 변경하는 것은 무례합니다.

솔루션 옵션 2 : 문자열이 이미 그늘에

  • 사용 "받는다는 그늘 - 플러그인"(구현하기가 더 복잡) 구금되어 신뢰로 트릭을 JVM의 JAXB 구현 및 성능 해킹을 사용하여 Fastinfoset 라이브러리의 클래스를 재 패키징하십시오. 결과는 로직이없는 구성 요소 여야합니다. 이 옵션은 선택 사항이며 Fastinfoset 코덱 구성 요소를 사용하는 사람들이 코덱 라이브러리에서 가져온 전이 의존성으로 인해 클래스 경로 충돌을 발생시키지 않도록합니다.
  • Fastinfoset 페이로드를 인코딩하고 디코딩하는 간단한 API를 제공하는 my-fastinfoset-codec 라이브러리를 만듭니다 (인수에 InputStream 및 OutputStream 사용, 디코더의 반환 형식에 XMLStreamReader 사용 고려). 리 패키징 된 Fastinfoset 라이브러리에 종속성을 추가하십시오. 이클립스를 사용하면 m2e의 "작업 공간 해상도"가 활성화되어있을 때 음영 처리 된 라이브러리를 잘 다루지 않으므로 코덱 프로젝트에서 사용하지 않도록 설정하십시오.
  • 리 패키징 된 Fastinfoset 라이브러리의 "StAXManager"를 확장하는 클래스를 my-fastinfoset-codec에 추가합니다. 이 클래스는 주어진 XMLStreamReader가 이미 NS와 태그 이름 문자열을 포함하고 있음을 jaxb에 알려주는 속성을 쉽게 설정해야합니다. 예는 다음과 같습니다 :
 
    package myrepackagedfastinfosetclassespackageprefix.shaded.com.sun.xml.fastinfoset.stax; 
    import myrepackagedfastinfosetclassespackageprefix.shaded.com.sun.xml.fastinfoset.stax.StAXManager; 
    public class JaxbStringInternSuppressionStaxManager extends StAXManager { 
     public JaxbStringInternSuppressionStaxManager() { 
      // Add to the allowable list of feature names so that the user may set these "StAXInputFactory" properties 
      super.features.put("org.codehaus.stax2.internNames", null); 
      super.features.put("org.codehaus.stax2.internNsUris", null); 
     } 

     /** 
     * This is an optimization. The FastInfoset libraries already intern strings and the JVM's jaxb implementation by default 
     * unnecessarily repeats that work. This is true at least for the 64 bit version of jdk1.8.0_121. 
     * 
     * The way that this workaround works is by piggybacking on a Jaxb optimization for the Woodstox parser. When we set 
     * these properties it tells jaxb that Woodstox has already interned the strings which causes it to disable its 
     * string interning. 
     * 
     * We did explore the cleaner option of pulling in the Maven "javax.xml:jaxb-impl" artifact as a dependency instead of using 
     * the JVM's jaxb library. That external jaxb library when used with the FastInfoset library does perform substantially better 
     * than the JVM's but isn't 100% as fast as the JVM's with interning disabled. The key reason that we quit exploring that solution 
     * is that when you repackage (via maven-shade-plugin) the jaxb libraries they no longer work with our standard jaxb binding 
     * maven components due to statements like "if (instanceof my_repackaging_project.shaded.XMLElement)" 
     * used during the data mapping process. 
     */ 
     public JaxbStringInternSuppressionStaxManager enableTrickToStopJaxbFromInterningStrings() { 
      super.setProperty("org.codehaus.stax2.internNames", true); 
      super.setProperty("org.codehaus.stax2.internNsUris", true); 
      return this; 
     } 
    } 

솔루션 옵션 3 : 오라클과 JVM 지원 계약이 충분한 사람들이 어떤 종류의 비 내부 fastinfoset 지원을 요청 티켓을 올립니다.

오라클이 주어진 XMLStreamReader에서이 Fastinfoset 구현이 인턴 문자열로 구성되었는지 확인하기 위해 JVM 제공 jaxb 구현을 가르치는 것이 상당히 간단하다고 생각합니다. 사용자 정의 접두사 패키지 이름으로 새로운 항아리를 만들기 위해 "받는다는 그늘 - 플러그인"또는 이와 유사한 사용할 수 있습니다

한 위의 솔루션 1에서 두 개의 항아리를 다시 패키지 : 못했죠

해결 가능성. 이것은 일부 바이올린 연주 후에이 라이브러리들과 함께 작동했습니다. 그러나 재 포장 된 jaxb 라이브러리는 이제 jaxb-RI에서 제작 한 OXM 객체에 새 음영 패키지 이름의 주석을달라고했습니다. 내 재 포장 솔루션은 모든 데이터를 내 개체에 매핑하지 않도록 표준 방식으로 제작되었습니다.OXM 바인딩 라이브러리가 재 패키징 된 jaxb 라이브러리를 사용하도록 지시하지 않거나, 이러한 주석에 사용 된 패키지를 변경하지 않도록주의 깊게 리 패키징하는 방법을 탐색하기에이 접근법을 좋아하지 않았습니다.

내가 탐구하지 않았다

솔루션 옵션 ". .internal을"

을 가지고있는 JVM의 fastinfoset 클래스를 사용하여 패키지 이름에. 그것들은 JVM과 함께 제공되는 jaxb 구현에서 잘 수행 될 것입니다.하지만 내부 api를 사용하여 지원 비용에 "미래의 나"를 노출하는 것을 거부합니다.

관련 문제