Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #35262 > unrolled thread

Restricting the memory usage of a Java program

Started byCecil Westerhof <Cecil@decebal.nl>
First post2016-08-11 23:42 +0200
Last post2016-08-11 18:24 -0400
Articles 9 — 3 participants

Back to article view | Back to comp.lang.java.programmer


Contents

  Restricting the memory usage of a Java program Cecil Westerhof <Cecil@decebal.nl> - 2016-08-11 23:42 +0200
    Re: Restricting the memory usage of a Java program Arne Vajhøj <arne@vajhoej.dk> - 2016-08-11 18:04 -0400
      Re: Restricting the memory usage of a Java program Cecil Westerhof <Cecil@decebal.nl> - 2016-08-12 10:34 +0200
        Re: Restricting the memory usage of a Java program Martin Gregorie <martin@address-in-sig.invalid> - 2016-08-12 10:08 +0000
        Re: Restricting the memory usage of a Java program Arne Vajhøj <arne@vajhoej.dk> - 2016-08-12 09:23 -0400
          Re: Restricting the memory usage of a Java program Cecil Westerhof <Cecil@decebal.nl> - 2016-08-13 01:11 +0200
            Re: Restricting the memory usage of a Java program Cecil Westerhof <Cecil@decebal.nl> - 2016-08-13 02:52 +0200
            Re: Restricting the memory usage of a Java program Arne Vajhøj <arne@vajhoej.dk> - 2016-08-12 21:05 -0400
    Re: Restricting the memory usage of a Java program Arne Vajhøj <arne@vajhoej.dk> - 2016-08-11 18:24 -0400

#35262 — Restricting the memory usage of a Java program

FromCecil Westerhof <Cecil@decebal.nl>
Date2016-08-11 23:42 +0200
SubjectRestricting the memory usage of a Java program
Message-ID<8760r7m18z.fsf@Equus.decebal.nl>
I made a little program for cropping images. When just starting it as
a Java program the memory usage was just way to much. So I wrote the
following script:
#!/usr/bin/env bash

declare -r CLASS=CropImage
declare -r MIN_MEM=128M
declare -r MAX_MEM=256M

# Make sure you are in the right directory.
# Only start the Java application when moving to the right directory was succesful.
cd "${0%/*}" && java "-Xms${MIN_MEM}" "-Xmx${MAX_MEM}" "${CLASS}" &

And now the memory consumption is much less and as far as I can see
without negative consequences for the program.

The values I use (128 MB and 256 MB) are just values I kind of
randomly choose. Is there a way to find ‘optimal’ values?


Bonus question: is there a way to limit the memory usage when the
program is started with:
    java CropImage
instead of the script?

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [next] | [standalone]


#35263

FromArne Vajhøj <arne@vajhoej.dk>
Date2016-08-11 18:04 -0400
Message-ID<noisp2$12e7$1@gioia.aioe.org>
In reply to#35262
On 8/11/2016 5:42 PM, Cecil Westerhof wrote:
> I made a little program for cropping images. When just starting it as
> a Java program the memory usage was just way to much. So I wrote the
> following script:
> #!/usr/bin/env bash
>
> declare -r CLASS=CropImage
> declare -r MIN_MEM=128M
> declare -r MAX_MEM=256M
>
> # Make sure you are in the right directory.
> # Only start the Java application when moving to the right directory was succesful.
> cd "${0%/*}" && java "-Xms${MIN_MEM}" "-Xmx${MAX_MEM}" "${CLASS}" &
>
> And now the memory consumption is much less and as far as I can see
> without negative consequences for the program.
>
> The values I use (128 MB and 256 MB) are just values I kind of
> randomly choose. Is there a way to find ‘optimal’ values?

System.gc();
Runtime rt = Runtime.getRuntime();
long actual_value = rt.totalMemory() - rt.freeMemory();
long good_value = SOME_MAGIC_FACTOR * actual_value;

Arne


[toc] | [prev] | [next] | [standalone]


#35266

FromCecil Westerhof <Cecil@decebal.nl>
Date2016-08-12 10:34 +0200
Message-ID<87wpjml720.fsf@Equus.decebal.nl>
In reply to#35263
On Friday 12 Aug 2016 00:04 CEST, Arne Vajhøj wrote:

> On 8/11/2016 5:42 PM, Cecil Westerhof wrote:
>> I made a little program for cropping images. When just starting it
>> as a Java program the memory usage was just way to much. So I wrote
>> the following script: #!/usr/bin/env bash
>>
>> declare -r CLASS=CropImage
>> declare -r MIN_MEM=128M
>> declare -r MAX_MEM=256M
>>
>> # Make sure you are in the right directory. Only start the Java
>> # application when moving to the right directory was succesful. cd
>> # "${0%/*}" && java "-Xms${MIN_MEM}" "-Xmx${MAX_MEM}" "${CLASS}" &
>>
>> And now the memory consumption is much less and as far as I can see
>> without negative consequences for the program.
>>
>> The values I use (128 MB and 256 MB) are just values I kind of
>> randomly choose. Is there a way to find ‘optimal’ values?
>
> System.gc();
> Runtime rt = Runtime.getRuntime();
> long actual_value = rt.totalMemory() - rt.freeMemory();
> long good_value = SOME_MAGIC_FACTOR * actual_value;

It is funny: I was always told that calling gc does not have an effect
on memory and that it can have a negative impact on performance. But I
saw a real difference. Maybe it is a good idea to call it once an
hour?

I added the following to my constructor:
    ses.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                long divideValue = 1024 * 1024;
                long freeMemory  = rt.freeMemory()  / divideValue;
                long totalMemory = rt.totalMemory() / divideValue;

                giveMessage(String.format("Maximum to use %d",
                                          rt.maxMemory() / divideValue));
                giveMessage(String.format("Before %d - %d = %d",
                                          totalMemory, freeMemory,
                                          totalMemory - freeMemory));
                System.gc();
                freeMemory  = rt.freeMemory()  / divideValue;
                totalMemory = rt.totalMemory() / divideValue;
                giveMessage(String.format("After  %d - %d = %d",
                                          totalMemory, freeMemory,
                                          totalMemory - freeMemory));
            }
        }, 15, 60, TimeUnit.MINUTES);

The function giveMessage prints the input string with a time stamp to
standard out.

The first time I ran it with:
        }, 0, 15, TimeUnit.MINUTES);

I ran it for little more as ten hours and with both I saw that the
free memory was the same after the gc. So it is really useful to get
an indication.


Maybe I should rewrite it as an utility function, so I could use it in
all my applications. And of-course I should log to a (SQLite) database
instead of standard out. (It should be called logMessage instead of
giveMessage.)


I also have an instance running without the gc. I should let it run
for at least a day to see what happens.

They start with:
- script version
09:43:54: Maximum to use 228
09:43:54: Before 123 - 64 = 59
09:43:54: After  123 - 69 = 54

- Java version
09:48:20: Maximum to use 3540
09:48:20: Before 240 - 172 = 68
09:48:20: After  240 - 186 = 54

- Java version without gc
09:49:23: Maximum to use 3540
09:49:23: Before 240 - 172 = 68
09:49:23: After  240 - 172 = 68

When it runs at least a day I will give an update.


It is clear that max memory default is quit large.
Without the script total memory is higher, but not that much. So maybe
I do not need the scripts to curtail memory usage. I save work and
when sometimes the application needs a lot more it is not curtailed.
Of-course 120 MB is a lot on an embedded device and when you would
have 20 Java applications it is going to count also, but at the moment
I am running on a desktop with enough memory and am not running scores
of Java applications.
I can always start limiting memory when it becomes tight and when I
also have some information about the usage …

Just to be sure: maxMemory cannot change during the run of a Java
application?


There is 28 MB difference between -Xmx and what maxMemory returns.
Where did it go?

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#35267

FromMartin Gregorie <martin@address-in-sig.invalid>
Date2016-08-12 10:08 +0000
Message-ID<nok76r$g9q$1@dont-email.me>
In reply to#35266
On Fri, 12 Aug 2016 10:34:15 +0200, Cecil Westerhof wrote:

> Maybe I should rewrite it as an utility function, so I could use it in
> all my applications. And of-course I should log to a (SQLite) database
> instead of standard out. (It should be called logMessage instead of
> giveMessage.)
>
That never hurts: I maintain a private library of useful stuff that tends 
to get into most of my programs because they make life easier, such as a 
command line parsing class and a general tracing and error reporting 
class, the latter giving runtime control of tracing detail and the option 
of wtiting tracing detail to a circular buffer that only gets displayed 
of an error is thrown - it provides a different view to stacktrace. 
Stacktrace shows where you are while the buffer dump shows how you got 
there.    
 
> There is 28 MB difference between -Xmx and what maxMemory returns. Where
> did it go?
>
Workspace used during JVM initialisation but still there because the gc 
hasn't (yet) been run?
 

-- 
martin@   | Martin Gregorie
gregorie. | Essex, UK
org       |

[toc] | [prev] | [next] | [standalone]


#35271

FromArne Vajhøj <arne@vajhoej.dk>
Date2016-08-12 09:23 -0400
Message-ID<nokil0$1ce1$1@gioia.aioe.org>
In reply to#35266
On 8/12/2016 4:34 AM, Cecil Westerhof wrote:
> On Friday 12 Aug 2016 00:04 CEST, Arne Vajhøj wrote:
>> On 8/11/2016 5:42 PM, Cecil Westerhof wrote:
>>> The values I use (128 MB and 256 MB) are just values I kind of
>>> randomly choose. Is there a way to find ‘optimal’ values?
>>
>> System.gc();
>> Runtime rt = Runtime.getRuntime();
>> long actual_value = rt.totalMemory() - rt.freeMemory();
>> long good_value = SOME_MAGIC_FACTOR * actual_value;
>
> It is funny: I was always told that calling gc does not have an effect
> on memory and that it can have a negative impact on performance. But I
> saw a real difference. Maybe it is a good idea to call it once an
> hour?

I doubt it.

System.gc is not something that makes sense to call as
part of normal execution.

But if one want to know how much heap space is in used
after GC has removed orphan objects, then it makes sense.

> I added the following to my constructor:
>     ses.scheduleAtFixedRate(new Runnable() {
>             @Override
>             public void run() {
>                 long divideValue = 1024 * 1024;
>                 long freeMemory  = rt.freeMemory()  / divideValue;
>                 long totalMemory = rt.totalMemory() / divideValue;
>
>                 giveMessage(String.format("Maximum to use %d",
>                                           rt.maxMemory() / divideValue));
>                 giveMessage(String.format("Before %d - %d = %d",
>                                           totalMemory, freeMemory,
>                                           totalMemory - freeMemory));
>                 System.gc();
>                 freeMemory  = rt.freeMemory()  / divideValue;
>                 totalMemory = rt.totalMemory() / divideValue;
>                 giveMessage(String.format("After  %d - %d = %d",
>                                           totalMemory, freeMemory,
>                                           totalMemory - freeMemory));
>             }
>         }, 15, 60, TimeUnit.MINUTES);
>
> The function giveMessage prints the input string with a time stamp to
> standard out.
>
> The first time I ran it with:
>         }, 0, 15, TimeUnit.MINUTES);
>
> I ran it for little more as ten hours and with both I saw that the
> free memory was the same after the gc. So it is really useful to get
> an indication.

Yes. It gives an indication of how much heap space is absolutely
required.

If you set Xmx lower than that then you run out of memory.

If you set Xmx just a little bit higher than that then GC run too
frequently and hurt throughput.

If you set Xmx extremely higher than that then GC will run very
rarely and can cause pauses (because it is GC'ing too much).

If you set Xmx sufficient higher then you should see good
throughput and minimal pausing.

> Maybe I should rewrite it as an utility function, so I could use it in
> all my applications.

I am just suggesting it for fine tuning what you want to set Xmx
to. Sort of a debugging tool. Not a production thing.

> Just to be sure: maxMemory cannot change during the run of a Java
> application?

That is my understanding. See previous post.

> There is 28 MB difference between -Xmx and what maxMemory returns.
> Where did it go?

I don't know.

Arne

[toc] | [prev] | [next] | [standalone]


#35280

FromCecil Westerhof <Cecil@decebal.nl>
Date2016-08-13 01:11 +0200
Message-ID<87fuq9lgzr.fsf@Equus.decebal.nl>
In reply to#35271
On Friday 12 Aug 2016 15:23 CEST, Arne Vajhøj wrote:

>> It is funny: I was always told that calling gc does not have an
>> effect on memory and that it can have a negative impact on
>> performance. But I saw a real difference. Maybe it is a good idea
>> to call it once an hour?
>
> I doubt it.
>
> System.gc is not something that makes sense to call as
> part of normal execution.
>
> But if one want to know how much heap space is in used
> after GC has removed orphan objects, then it makes sense.
>
>> I added the following to my constructor:
>> ses.scheduleAtFixedRate(new Runnable() {
>> @Override
>> public void run() {
>> long divideValue = 1024 * 1024;
>> long freeMemory  = rt.freeMemory()  / divideValue;
>> long totalMemory = rt.totalMemory() / divideValue;
>>
>> giveMessage(String.format("Maximum to use %d",
>> rt.maxMemory() / divideValue));
>> giveMessage(String.format("Before %d - %d = %d",
>> totalMemory, freeMemory,
>> totalMemory - freeMemory));
>> System.gc();
>> freeMemory  = rt.freeMemory()  / divideValue;
>> totalMemory = rt.totalMemory() / divideValue;
>> giveMessage(String.format("After  %d - %d = %d",
>> totalMemory, freeMemory,
>> totalMemory - freeMemory));
>> }
>> }, 15, 60, TimeUnit.MINUTES);
>>
>> The function giveMessage prints the input string with a time stamp
>> to standard out.
>>
>> The first time I ran it with:
>> }, 0, 15, TimeUnit.MINUTES);
>>
>> I ran it for little more as ten hours and with both I saw that the
>> free memory was the same after the gc. So it is really useful to
>> get an indication.
>
> Yes. It gives an indication of how much heap space is absolutely
> required.
>
> If you set Xmx lower than that then you run out of memory.
>
> If you set Xmx just a little bit higher than that then GC run too
> frequently and hurt throughput.
>
> If you set Xmx extremely higher than that then GC will run very
> rarely and can cause pauses (because it is GC'ing too much).
>
> If you set Xmx sufficient higher then you should see good
> throughput and minimal pausing.

I am thinking about setting it to two to four times the max value of
used after gc. It is of-course depending on the type of application
and the way it is used. When the usage changes, the needed memory
requirement can be changed also.


>> Maybe I should rewrite it as an utility function, so I could use it
>> in all my applications.
>
> I am just suggesting it for fine tuning what you want to set Xmx
> to. Sort of a debugging tool. Not a production thing.

That is where the whole exercise started for: getting a good value for
Xmx. When setting this to 256 MB I see that the application when not
really used uses about half of the memory as when Xmx not used. In
that case it could be halved. But I should look for the case that the
application is used of-course. ;-)

By the way: there is now way to get the value for minMemory?


>> Just to be sure: maxMemory cannot change during the run of a Java
>> application?
>
> That is my understanding. See previous post.

But it can, I just saw:
    freeAfter freeBefore maxMemory totalAfter totalBefore
    "185"	  "65"	     "239"	   "239"	  "242"
    "101"	  "96"	     "228"	   "155"	  "155"

So first maxMemory was 228. An hour later total was 242 before gc.
After gc total was 239 and maxMemory was changed from 228 to 239.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#35284

FromCecil Westerhof <Cecil@decebal.nl>
Date2016-08-13 02:52 +0200
Message-ID<8760r5lccf.fsf@Equus.decebal.nl>
In reply to#35280
On Saturday 13 Aug 2016 01:11 CEST, Cecil Westerhof wrote:

>>> Just to be sure: maxMemory cannot change during the run of a Java
>>> application?
>>
>> That is my understanding. See previous post.
>
> But it can, I just saw:
> freeAfter freeBefore maxMemory totalAfter totalBefore
> "185"	  "65"	     "239"	   "239"	  "242"
> "101"	  "96"	     "228"	   "155"	  "155"
>
> So first maxMemory was 228. An hour later total was 242 before gc.
> After gc total was 239 and maxMemory was changed from 228 to 239.

But it is also given back, the next line (an hour later) reeds:
freeAfter freeBefore maxMemory totalAfter totalBefore
"120"     "42"       "228"     "174"      "174"

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#35285

FromArne Vajhøj <arne@vajhoej.dk>
Date2016-08-12 21:05 -0400
Message-ID<nolro4$1ckv$1@gioia.aioe.org>
In reply to#35280
On 8/12/2016 7:11 PM, Cecil Westerhof wrote:
> By the way: there is now way to get the value for minMemory?

That info is water under the bridge.

But if you really want it then look at:

ManagementFactory.getRuntimeMXBean().getInputArguments()

Arne

[toc] | [prev] | [next] | [standalone]


#35264

FromArne Vajhøj <arne@vajhoej.dk>
Date2016-08-11 18:24 -0400
Message-ID<noitvc$1436$1@gioia.aioe.org>
In reply to#35262
On 8/11/2016 5:42 PM, Cecil Westerhof wrote:
> Bonus question: is there a way to limit the memory usage when the
> program is started with:
>     java CropImage
> instead of the script?

You can start JVM via JNI (really just your own java executable
replacement) with the Xmx you want.

But when the JVM is running then I don't know any way via
JMX or JNI to change the value.

Many JVM's require heap to be contiguous, so trying to
increase Xmx later may not be possible.

Arne

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.java.programmer


csiph-web