Browse Source
Previously, working with a JarFile created a large amount of garbage that was allocated on the thread local allocation buffer (TLAB). The TLAB allocations made a significant contribution to GC pressure and slowed down startup. This commit reduces the amount of garbage by making a number of changes. Reading from a RandomAccessDataFile has been reworked to avoid creating new RandomAccessFile instances. A single RandomAccessFile is now created for an entire jar file and it is used to read data from anywhere in that jar file, including entries in nested jar files. To ensure that reads remain thread-safe, a lock is taken on the RandomAccessFile that is shared by all RandomAccessDataFile instances that are provided access to (portions of) the same jar file. Reading all of the bytes from a RandomAccessData has been reworked to avoid the use of an InputStream that was created, used to read the data, and then thrown away. In place of the InputStream-based mechanism a method has been introduced that returns all of the RandomAccessData as a byte[]. Building on this change, a method has also been introduced to read a portion of a RandomAccessData as a byte[]. This avoids the need to create a new RandomAccessData subsection where the subsection was only used to read its entire contents and then thrown away. Decoding of an MS-DOS datetime has been reworked to use LocalDataTime rather than GregorianCalendar. The former produces less garbage than the latter. Closes gh-12226pull/12272/head
16 changed files with 115 additions and 422 deletions
@ -1,60 +0,0 @@
@@ -1,60 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2017 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.boot.loader.data; |
||||
|
||||
import java.io.ByteArrayInputStream; |
||||
import java.io.InputStream; |
||||
|
||||
/** |
||||
* {@link RandomAccessData} implementation backed by a byte array. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
public class ByteArrayRandomAccessData implements RandomAccessData { |
||||
|
||||
private final byte[] bytes; |
||||
|
||||
private final long offset; |
||||
|
||||
private final long length; |
||||
|
||||
public ByteArrayRandomAccessData(byte[] bytes) { |
||||
this(bytes, 0, (bytes == null ? 0 : bytes.length)); |
||||
} |
||||
|
||||
public ByteArrayRandomAccessData(byte[] bytes, long offset, long length) { |
||||
this.bytes = (bytes == null ? new byte[0] : bytes); |
||||
this.offset = offset; |
||||
this.length = length; |
||||
} |
||||
|
||||
@Override |
||||
public InputStream getInputStream(ResourceAccess access) { |
||||
return new ByteArrayInputStream(this.bytes, (int) this.offset, (int) this.length); |
||||
} |
||||
|
||||
@Override |
||||
public RandomAccessData getSubsection(long offset, long length) { |
||||
return new ByteArrayRandomAccessData(this.bytes, this.offset + offset, length); |
||||
} |
||||
|
||||
@Override |
||||
public long getSize() { |
||||
return this.length; |
||||
} |
||||
|
||||
} |
||||
@ -1,55 +0,0 @@
@@ -1,55 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2017 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.boot.loader.data; |
||||
|
||||
import java.io.InputStream; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
import org.springframework.boot.loader.data.RandomAccessData.ResourceAccess; |
||||
import org.springframework.util.FileCopyUtils; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link ByteArrayRandomAccessData}. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
public class ByteArrayRandomAccessDataTests { |
||||
|
||||
@Test |
||||
public void testGetInputStream() throws Exception { |
||||
byte[] bytes = new byte[] { 0, 1, 2, 3, 4, 5 }; |
||||
RandomAccessData data = new ByteArrayRandomAccessData(bytes); |
||||
InputStream inputStream = data.getInputStream(ResourceAccess.PER_READ); |
||||
assertThat(FileCopyUtils.copyToByteArray(inputStream)).isEqualTo(bytes); |
||||
assertThat(data.getSize()).isEqualTo(bytes.length); |
||||
} |
||||
|
||||
@Test |
||||
public void testGetSubsection() throws Exception { |
||||
byte[] bytes = new byte[] { 0, 1, 2, 3, 4, 5 }; |
||||
RandomAccessData data = new ByteArrayRandomAccessData(bytes); |
||||
data = data.getSubsection(1, 4).getSubsection(1, 2); |
||||
InputStream inputStream = data.getInputStream(ResourceAccess.PER_READ); |
||||
assertThat(FileCopyUtils.copyToByteArray(inputStream)) |
||||
.isEqualTo(new byte[] { 2, 3 }); |
||||
assertThat(data.getSize()).isEqualTo(2L); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue