@Contended padding false sharing
@Contended and false sharing
Original: http://robsjava.blogspot.com/2014/03/what-is-false-sharing.html
Java8 introduced @Contented
this new annotation to reduce False Sharing
the occurrence of false sharing ( ). This article introduces @Contented
annotations and explains why and False Sharing
how they affect performance.
cache line
When the CPU reads memory data, it does not read only one byte at a time, but reads a 64-byte length of contiguous memory blocks (chunks of memory), which we call cache lines.
Suppose you have two threads (Thread1 and Thread2) both modifying the same volatile
variable x
:
1
|
volatile long x;
|
If Thread1 changes the value of x first, and then Thread2 reads it:
1
2
|
Thread 1 : x= 3 ;
Thread 2 : System.out.print(x);
|
Then all 64-byte values on the cache line where x is located are reloaded, because the exchange of data between CPU cores is in the smallest unit of cache line. Of course it is possible for Thread1 and Thread2 to run on the same core, but we assume here that the two threads run on different cores.
It is known that the long type occupies 8 bytes, and the length of the cache line is 64 bytes, then a cache line can store 8 long type variables, we already have a long type x, assuming that there are other cache lines where x is located 7 long variables, v1 to v7:
1
|
x, v1 , v2 , v3 , v4 , v5 , v6 , v7
|
False Sharing
This cache line can be accessed by many threads. If one of them modifies v2, it will cause both Thread1 and Thread2 to reload the entire cache line. You may be wondering why modifying v2 causes Thread1 and Thread2 to reload the cache line, after all, it just modifies the value of v2. Although these modifications are logically independent of each other, the data on the same cache line is maintained uniformly, and the granularity of consistency is not reflected in a single element. This unnecessary data sharing is called "false sharing" (False Sharing).
Padding
A CPU core executes hundreds of instructions to load a cache line. If one core is waiting for another core to reload the cache line, then it has to wait there, called stall
(stopping). Reducing false sharing also means reducing the stall
occurrences. One of the means is to use padding data to ensure that two variables that should be located in the same cache line must be located in different locations when accessed by multiple threads. cache line.
In the following example, we try to pad the sum so that the x
sum v1
is on a different cache line:
1
2
3
4
5
6
7
8
9
10
11
|
public class FalseSharingWithPadding {
public volatile long x;
public volatile long p2; // padding
public volatile long p3; // padding
public volatile long p4; // padding
public volatile long p5; // padding
public volatile long p6; // padding
public volatile long p7; // padding
public volatile long p8; // padding
public volatile long v1;
}
|
Before you consider using padding, it is important to understand that the JVM may clear or rearrange the position of useless fields, which may inadvertently introduce false sharing. There is also no way for us to specify where objects reside within the heap.
In order to avoid useless fields from being eliminated, we usually volatile
decorate them. Personally, it is recommended to fill in only the classes that are in a state of fierce competition, and generally only by analyzing their performance can the difference in performance be found. Usually in performance analysis, it is best to sample it after 10,000 iterative visits, which can eliminate the impact of the runtime optimization strategy of the JVM itself.
Java8和@Contended
In addition to filling the fields, there is a refreshing method, which is to annotate the fields that need to avoid falling into false sharing. This annotation implies that the JVM should put the fields into different cache lines, which is also related to JEP142. content.
This JEP introduces @Contented
annotations. Fields modified by this annotation should reside in a different location than other fields.
1
2
3
4
5
|
public class Point {
int x;
int y;
}
|
The above code puts x and y on different cache lines. The @Contented annotation moves y away from the head of the object, (to avoid being loaded on the same cache line as x).
refer to
http://openjdk.java.net/projects/jdk8/features
http://beautynbits.blogspot.co.uk/2012/11/the-end-for-false-sharing-in-java.html
http://openjdk.java.net/jeps/142
http://mechanical-sympathy.blogspot.co.uk/2011/08/false-sharing-java-7.html
http://stackoverflow.com/questions/19892322/when-will-jvm-use-intrinsics
https://blogs.oracle.com/dave/entry/java_contented_annotation_to_help