4

Background:

We have a vendor-supplied Java application that has a somewhat large Java Heap. Without going into too much info, the app is a black box to us, yet we feel we need to take it upon ourselves to try to tune the performace and fix problems.

The 64bit SunOS 10 machine has 16GB ram and the only non-system app that is running is the JVM for this app. The 64bit JVM runs in JBoss which I think is irrelevant to this discussion and the max heap size is 8GB, which I think is relevant.

The issue recently is that we have been getting various out of memory errors. The heap is not full when these errors occur and the error asks 'Out of Swap Space?'. The vendor wants us to just increase swap from 2GB to 4GB, This is on a system with 16GB and out app is only 8GB. We feel this will be a bad idea for performance.

My question:

So one thing we found that was the file caching uses up all the remaining free memory to increase performance. Normally not a problem, but it apparently fragments the memory. As the Hotspot JVM requires contiguous memory space, we have understood that this memory fragmentation results in the use of the swap space that is not fragmented.

However, I am not sure if I understand the relationship between the fragmentation and the requirement of contiguous memory. Surely the fragmentation is just referring to fragmentation of the physical ram. With virtual memory, it is entirely possible to allocate a contiguous chunk of ram without it being backed by a contiguous chunk of ram. In other words, a non-contiguous chunk of physical memory would appear to a running process as a contiguous chunk of virtual memory.

So, I guess, there was no one sentence question in there, but does anyone know more on this subject and can chime in? Any links that refer to this contiguous memory issue on 64 bit systems?

What I found so far:

So far, every reference I have found to the 'contiguous memory' problem has been more related to how the virtual address space is laid out in 32bit address systems. As we are running a 64 bit system (with, I think, 48 bit addressing), there is plenty of virtual address space to allocate large contiguous chunks.

I have been looking all over the internet for this information but have been unable, thus far, to find the information I am looking for.

Updates:

  • To be clear, I was not trying to get an answer to why I was getting OOM errors, but rather trying to understand the relationship between possibly fragmented system RAM and the contiguous chunk of virtual memory needed by java.
  • prstat -Z

ZONEID    NPROC  SWAP   RSS MEMORY      TIME  CPU ZONE  
     0       75 4270M 3855M    24%  92:24:03 0.3% global

  • echo "::memstat" | mdb -k

Page Summary                Pages                MB  %Tot    
------------     ----------------  ----------------  ----  
Kernel                     326177              2548   16%  
ZFS File Data              980558              7660   48%  
Anon                       561287              4385   27%  
Exec and libs               12196                95    1%  
Page cache                  17849               139    1%  
Free (cachelist)             4023                31    0%  
Free (freelist)            156064              1219    8%  

Total                     2058154             16079  
Physical                  2042090             15953  

  • Where I previously thought that the ZFS File Data was memory that is freely available, I have since learned that this is not the case and could well be the cause for errors.

  • vmstat 5 5


kthr      memory            page            disk          faults      cpu  
r b w   swap  free  re  mf pi po fr de sr vc vc vc --   in   sy   cs us sy id  
0 0 0 2161320 2831768 12 55 0  0  0  0  0  3  4 -0  0 1089 1320 1048  1  1 98  
0 0 0 819720 1505856 0  14  0  0  0  0  0  4  0  0  0 1189  748 1307  1  0 99  
0 0 0 819456 1505648 0   1  0  0  0  0  0  0  0  0  0 1024  729 1108  0  0 99  
0 0 0 819456 1505648 0   1  0  0  0  0  0  0  0  0  0  879  648  899  0  0 99  
0 0 0 819416 1505608 0   1  0  0  0  0  0  0  3  0  0 1000  688 1055  0  0 99  

  • These command outputs were taken when the application was running in a healthy state. We are now monitoring all of the above and logging it in case we see the swap space errors again.

  • The following is after the JVM had grown to 8GB and then was restarted. The effect of this is that the ZFS ARC has shrunk (to 26% RAM) until it grows again. How do things look now?

  • vmstat 5 5


kthr      memory            page            disk          faults      cpu
r b w   swap  free  re  mf pi po fr de sr vc vc -- --   in   sy   cs us sy id
0 0 0 1372568 2749528 11 41 0  0  0  0  0  2  3  0  0  713  418  539  0  0 99
0 0 0 3836576 4648888 140 228 0 0 0  0  0  0  0  0  0 1178 5344 1117  3  2 95
0 0 0 3840448 4653744 16 45 0  0  0  0  0  0  0  0  0 1070 1013  952  1  3 96
0 0 0 3839168 4652720 6 53  0  0  0  0  0  0  0  0  0  564  575  313  0  6 93
0 0 0 3840208 4653752 7 68  0  0  0  0  0  3  0  0  0 1284 1014 1264  1  1 98

  • swap -s

total: 4341344k bytes allocated + 675384k reserved = 5016728k used, 3840880k available


Tom17
  • 406
  • 5
  • 18
  • May be related to this: http://bugs.sun.com/view_bug.do?bug_id=6973402. You are not specifying a **fundamental** information, that is what version of HotSpot JVM you are running. – Viruzzo Feb 29 '12 at 14:23
  • We are using 1.6.0_18, however, I am not looking for a bug fix. We know there are heap related bugs in this version and we have finally persuaded the vendor to allow us to move to the latest version of Java. What I am looking for is a better understanding of the correlation between this need for contiguous memory and the supposed fragmentation of memory due to OS caching... – Tom17 Feb 29 '12 at 14:34
  • It seems just nonsense to me: allocation of physical memory is only an OS-side problem, the application should only work on its virtual memory (that is contiguous by nature); exactly where have you found about this supposed need for contiguous space? BTW this is not a matter of upgrading to Java 7, but to the latest version of Java 6, something that should be done without asking the implementor of the Java application (minor versions being backwards compatible). – Viruzzo Feb 29 '12 at 14:41
  • Increasing the swap area size would in no way be a bad idea for performance. What is bad for performance is not enough RAM. The size of the swap has no impact on performance, this is a common misconception. You should post your memory usage (both physical and virtual) at the time the OOM exception occurs. Heap memory is not the only one the JVM uses. How many threads do you have ? What is the stack size ? Is your java application spawning external processes ? – jlliagre Feb 29 '12 at 14:44
  • Well that was my understanding too (That fragmentation of memory is an OS specific thing and that the process only sees contiguous virtual memory). With this in mind, the whole idea of fragmentation being an issue is nonsense as you say. I'm just trying to get a better understanding of this and to find something concrete to show/explain to the vendor. And yes, I meant the latest version of Java 6 (1.6.0_31). We cannot just upgrade to this without vendor approval or we lose any 'support' from them :) – Tom17 Feb 29 '12 at 14:46
  • @jlliagre It's next to impossible to see how much ram is 'free' due to most of the free ram being used by the OS for file caching. The result is that system tools such as top are only showing ~700MB free even when the system is healthy. There are no external processes, there are thousands of threads. eed to check the stack size, but can the non-heap portion of the JVM really approach 8GB? – Tom17 Feb 29 '12 at 14:48
  • Free RAM is available RAM. The fact the OS might use this available RAM not to waste it doesn't matter. File cache is free and available RAM as far as java is concerned. Are you completely sure you aren't using (or an underlying library) Runtime.exec() ? – jlliagre Feb 29 '12 at 15:04
  • The issue with the available RAM thing is this: It appears that the OS is using the free RAM as cache, and this is OK as any process can use it when it's needed. Someone has suggested that this caching 'fragments' the ram and then the JVM is not able to use it as it needs contiguous ram. My understanding is that this is incorrect (as mentioned by Viruzzo) as the JVM only needs contiguous ram in its own virtual address space. The contiguous/fragmented nature of the physical ram that the OS sees has no correlation to the contiguous requirement of virtual memory that the JVM process needs. Right? – Tom17 Feb 29 '12 at 15:26
  • Yes, ZFS. We are looking to reduce its cache usage to reduce the fragmentation, but it seems this could be a moot point if my understanding is correct. – Tom17 Feb 29 '12 at 15:27
  • 1
    Your understanding is incorrect. You insist writing you have enough memory while you have not. ZFS ARC cache is handled slightly differently than file system cache (UFS). It is not (immediately) available memory. This is not related at all with JVM heap fragmentation. – jlliagre Feb 29 '12 at 18:12
  • I think the ZFS ARC cache is key here. I have read up more on it and as you say, it does not work the same as UFS. We need to reduce the ZFS ARC cache max size. Our unix admin insisted that memory cached by ZFS was freely available (as with UFS), but that is simply incorrect. The whole fragmentation issue is a red herring I think, a throwback from 32bit issues. – Tom17 Feb 29 '12 at 19:00

2 Answers2

1

When an error message suggests the swap space might not be large enough, I usually trust it and increase the swap size significantly.

I would so suggest you to do it first, up to 4 GB or even 8 GB and see what happens. Enlarging the swap has no impact whatsoever on performance. This is a common misconception. What impacts performance is the lack of RAM, not too large a swap area.

Only if the issue is still present after the change do I try to investigate alternative tracks, like perhaps the memory fragmentation one.

Edit:

From your memstat, prstat and vmstat output, it is clear your system is out of virtual memory. There is absolutely no need to investigate other unusual causes like memory fragmentation. You have more free RAM (~1.5G) than free virtual memory (~800MB). That means there are a lot of unused (yet) memory reservations. Again, just add some swap space to fix that. That is not going to have any performance impact as you have enough RAM.

Edit: (part 2)

Now we know you are using ZFS, as your application can use up to 8 GB (and even more if we take into account non heap memory), you should reduce the max ARC size to allow immediate availability of these 8 GB to the JVM, instead of relying of the self adjustments the OS is doing, which might currently be confused by the undersized swap. See the Limiting the ARC cache chapter in the ZFS evil tuning guide for details on how to do this.

jlliagre
  • 29,783
  • 6
  • 61
  • 72
  • OK, I am not the unix sysadmin, just trying to work this out as our sysadmin is less knowledgeable than me on this. So please, could you explain the above a little more? From what I could see, the outputs I provided just show that 43% of the RAM is being used by ZFS File Data. In other words, 43% RAM would be free if it was not for the ZFS Cache... – Tom17 Feb 29 '12 at 22:28
  • Also, I came here to find a way to prove that it was *not* fragmentation, that was my badly worded point :) – Tom17 Feb 29 '12 at 22:29
  • 1
    Don't confuse virtual and physical memory. Your OS is too short on virtual memory but not on physical one. Just capping ZFS ARC size would indeed be a solution but not necessarily the most efficient. You should do both. – jlliagre Mar 01 '12 at 00:17
  • I guess i'll never understand that. Why would I want to use disk based memory (virtual memory = swap + free physical RAM, right?) if we sized a machine such that we only wanted to use physical RAM. Anyway, thanks for trying to help me understand all this. Guess I am a lost cause ;) – Tom17 Mar 01 '12 at 01:28
  • 1
    Don't worry, this is a very common misunderstanding. In any case, I don't suggest to use that swap memory, just that it exists. However, I just noticed something odd. You wrote your application was using 8 GB but apparently, it is using less than 4.2 GB. I asked you to post the JVM options used but you didn't do it. Can you add them and `swap -s` output too to your question ?. By the way, virtual memory = all swap area size + all physical memory - kernel used physical memory. Virtual memory is often referred to as "swap" in Solaris terminology, which can be confusing. – jlliagre Mar 01 '12 at 08:35
  • As you are suspecting, Xms is not set to Xmx, despite me recomending it to the vendor. As such, the JVM varies in sise from ~1GB to 8GB. Still don't see why we should have to use swap (yes, it gets used when the problem occurs) while ZFS gets to use RAM. Anyway, I am now logging the output of all these commands so I can get a better idea of what happens when it actually crashes. Thank you for your help - you have pointed me in lots of new directions and I have learned a LOT in the last day :) – Tom17 Mar 01 '12 at 12:49
  • 1
    "yes, it gets used when the problem occurs" How do you measure swap usage ? By the way, if you appreciate my help and answers, feel free to accept my reply and/or vote it up ... – jlliagre Mar 01 '12 at 13:20
  • I'm not a fan of chatting. I guess you voted up my comment but fail to either accept my initial answer or vote it up. If there is still something you disagree with or fail to understand in that answer, don't hesitate asking here. – jlliagre Mar 01 '12 at 18:13
  • OK, I was worried about 'over chatting' in here due to the warning :) To be honest, we have not been constantly monitoring thus far. We have sar reports that run 24x7, but that is it. From my understanding, having ZFS in the mix makes a lot of the 'legacy' tools such as sar, swap, vmstat etc read incorrectly. So given that we apparently don't know how to measure these things correctly, how do you suggest that we measure swap usage? :) – Tom17 Mar 01 '12 at 23:22
  • And I am hesitant to vote-up your answer as I don't yet understand how it can be possible that we are running out of RAM. When I can understand and accept that, I can upvote. Now, I did notice that on another question somewhere you mentioned that if you have 'too much' RAM, then a swap file would not be needed. The way we see it, we do have too much RAM which is why we considered this option. – Tom17 Mar 01 '12 at 23:25
  • The legacy tools are not providing incorrect statistics. They tell you are out of RAM and have an undersized swap. You aren't in the "too much" RAM situation, especially as you have not enough swap so part of your RAM is unusable and wasted. You are also using ZFS with its default configuration which is not adapted to your context. http://www.solarisinternals.com/wiki/index.php/ZFS_Evil_Tuning_Guide#Limiting_the_ARC_Cache. Even while you properly tune the ARC cache, you probably still need to increase the swap size. By the way, you didn't provide `swap -s` output. – jlliagre Mar 02 '12 at 08:16
  • Yep, reducing the ZFS ARC is one of the first things we wanted to do. I think it is the way forward for us. I still fail to see how a 16GB system only running one 4-8GB Java app is anything other than 'too much RAM'. How is it possible that the OS itself is using over 8GB? So how much memory would you consider 'too much memory' for one 8GB JVM? I'll get onto the swap -s output when I get to work. – Tom17 Mar 02 '12 at 13:38
  • Okay, again some misunderstanding here. The OS itself is using more than 10 GB in the memstat output you posted. ZFS is part of the OS and you didn't mentioned you were using ZFS before I asked about it. This is sufficient to assert your system has not enough RAM **available** when the problem occurs. That it doesn't means you should add more RAM. 16 GB looks indeed sufficient for your use and adding RAM wouldn't even solve the issue. The two issues are that your swap is undersized and your ZFS arc cache isn't properly tuned. – jlliagre Mar 02 '12 at 20:55
  • Definitely misunderstanding then. I mentioned that we are using ZFS in 3 comments, including the first comment to your answer :). This was before I knew to add further info in the original question - i'm new here, bear with me :). So I guess as it was not clear that I was implying that we were using ZFS, and I guess I thought the fact that I was using ZFS is being glossed over. As I previously mentioned, reducing the ZFS ARC is one of the first things we wanted to do, but I was starting to doubt that based on what you were saying lol. – Tom17 Mar 03 '12 at 00:43
  • You didn't mentioned you were using ZFS before I asked "Are you using ZFS" in your initial question's comment. I was then answering to your question about memory fragmentation first, which is the question asked. I was confused by your comment about "free ram used by the cache" which describes UFS cache, not ARC with which used RAM is not reported as free. I'm afraid you still overlook the fact your swap is undersized, regardless of any other point. You are wasting 800 MB of RAM according to your last vmstat output and would likely waste much more should the JVM be configured with Xms = Xmx. – jlliagre Mar 03 '12 at 09:03
0

You can get this error if you have run out of main+swap space. While a 2 GB swap is pretty small these days, if you are having to use swap space you do have a performance problem as it means you are forcing applications to swap to disk.

Increasing the maximum heap in this situation won't help as the problem is a lack of memory. It could even make it more likely to happen.

The solution may be to use less memory (by reducing other application running on the system) or increasing your main memory (16 GB isn't that much for a server these days, my home PC has 24 ;)


EDIT: Another thing which I have seen cause this problem is heavy use of direct memory with heap memory. e.g. by default your maximum direct memory is the same as your maximum heap size. This means your application could be using almost 8 GB of direct memory before using all the heap. The application can find the OS doesn't have enough main+swap space to allocate memory to the heap and can die.

I tend to use direct memory as much as possible, but this is done to avoid using much heap. ;)

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Thanks for the answer. I agree that 16GB is not a huge amount, but the 8GB JVM is the only non-os component running on the server. I don't think the os itself needs 8GB to run, does it? ;) – Tom17 Feb 29 '12 at 15:07
  • @Tom17, the OS might. Please provide some data about your memory usage to clarify. `echo ::memstat | mdb -k` and `prstat -Z` output would be great. – jlliagre Feb 29 '12 at 15:29
  • @Peter Lawrey: On Solaris, an "out of swap space" message doesn't necessarily means that space will be used (i.e. paginated), so there might not be a performance problem. – jlliagre Feb 29 '12 at 15:32
  • prstat -Z ZONEID NPROC SWAP RSS MEMORY TIME CPU ZONE 0 94 3661M 3479M 21% 29:43:49 0.8% global This is when top is reporting only 1GB free. Interesting. It shows, I think, that not much memory is being used, as I suspected. I don't have root right now so I can't do mdb -k. – Tom17 Feb 29 '12 at 16:03
  • FWIW, our unix admin wants to have zero swap as we have ample memory and no need for it. prstat indicates that only 21% of memory is in use. I will have to try that again when the JVM is crashing if I can catch it. – Tom17 Feb 29 '12 at 16:11
  • If you are getting OutOfMemoryErrors, it may be premature to assume you have ample memory. ;) – Peter Lawrey Feb 29 '12 at 16:12
  • We are getting OutOfMemory errors due to swap space running out, even though there is multiple GB of free RAM. The question bugging us is, why is it trying to use swap space instead of ram. Some are saying that this is because of the aforementioned fragmentation. – Tom17 Feb 29 '12 at 16:20
  • Memory could be reserved, e.g. for large/huge pages. On linux I would look at `/proc/meminfo` – Peter Lawrey Feb 29 '12 at 16:28
  • Page Summary Pages MB %Tot Kernel 274296 2142 13% ZFS File Data 1081113 8446 53% Anon 487193 3806 24% Exec and libs 9598 74 0% Page cache 17097 133 1% Free (cachelist) 2169 16 0% Free (freelist) 186688 1458 9% Total 2058154 16079 Physical 2042090 15953 – Tom17 Feb 29 '12 at 16:43
  • 1
    Please post the information in your original question, not in comments and add `vmstat 5 5` output. What are the JVM -X* options used ? – jlliagre Feb 29 '12 at 18:06