- Регистрация
- 1 Мар 2015
- Сообщения
- 1,481
- Баллы
- 155
Let's start with the obvious, Java is great. It’s got a garbage collector, it keeps your hands mostly clean of manual memory management, and it’ll let you write code that just works. Until it doesn’t... Until that sweet little app of yours starts slowing down like it’s stuck in mud and your grafana memory usage chart looks like it’s climbing Everest with no plans to come back.
So yes... Java handles memory for you. But if you don’t understand what it’s doing behind the scenes, it’s only a matter of time before your app becomes jabba the hutt.
Let’s talk about how not to let that happen.
The Garbage Collector Is Not Your Maid
Java's garbage collector is fantastic. It takes care of unused objects so you don’t have to manually free() them like in C. But here’s the catch - the garbage collector only collects what it knows is garbage (shocker). If you're still holding references to unused objects even accidentally... It won’t touch them.
This is how memory leaks happen in Java.
Example?
Garbage Collection isn't magic. It's bookkeeping. If your bookkeeping is bad, your memory goes missing (I wish I came up with that).
Be Wary of Collections
The humble Listor Mapis often the first suspect when memory issues arise. Why you ask? Because we love shoving things in them and then forgetting about them.
Growing but not shrinking... Collections grow automatically, but they don’t shrink unless you ask them to.
Unbounded queues or caches? If you’re putting things in and never evicting them, guess what? That’s not a cache. That’s hoarding.
Tip: Use WeakHashMap when possible for caches - or find some good libs online.
Creating a lot of short lived objects isn’t always bad... modern JVMs are optimized for this. But if you’re doing it in tight loops or in performance critical paths, it can hurt.
Examples:
Ye Ol' String... Everyone’s favourite (probably the first data type you learnt when writing a HelloWorld app) but it’s also a memory hog if you’re not careful.
Every String in Java is immutable. So str += "To Infinity And Beyond!" inside a loop? That’s creating a whole new String each time (also your memory usage really will go to infinity and beyond... sorry ha!).
Some history for you (Something I learnt recently), old school Java used to store strings in the PermGen. Sure that's gone in newer versions BUT poorly managed strings still cause bloat.
Tuning the JVM Isn’t Cheating
The JVM is powerful, but it doesn’t know your app. That’s your job.
You don’t need to be a JVM engineer to write memory efficient code... But you do need to know how memory works. Blind trust in the garbage collector will only get you so far - maybe pretty far (depending on what you're building) but when your memory usage is going to the moon? Goodluck, I hope you have lots of coffee and a nice boss.
So take the time:
You'll eventually start doing these things subconsciously..
And yes... every now and then... read a heap dump. It builds character.
A few things I’d love to discuss:
Still no gin,
Rus
So yes... Java handles memory for you. But if you don’t understand what it’s doing behind the scenes, it’s only a matter of time before your app becomes jabba the hutt.
Let’s talk about how not to let that happen.
The Garbage Collector Is Not Your Maid
Java's garbage collector is fantastic. It takes care of unused objects so you don’t have to manually free() them like in C. But here’s the catch - the garbage collector only collects what it knows is garbage (shocker). If you're still holding references to unused objects even accidentally... It won’t touch them.
This is how memory leaks happen in Java.
Example?
- Caching too aggressively.
- Static fields that accumulate data over time.
- Listeners that never get removed.
- Sessions that never end.
Garbage Collection isn't magic. It's bookkeeping. If your bookkeeping is bad, your memory goes missing (I wish I came up with that).
Be Wary of Collections
The humble Listor Mapis often the first suspect when memory issues arise. Why you ask? Because we love shoving things in them and then forgetting about them.
Growing but not shrinking... Collections grow automatically, but they don’t shrink unless you ask them to.
Unbounded queues or caches? If you’re putting things in and never evicting them, guess what? That’s not a cache. That’s hoarding.
Tip: Use WeakHashMap when possible for caches - or find some good libs online.
Object Creation Matters More Than You ThinkIn a weak hashmap, items can be cleared by the garbage collector if nothing else is using the key
Creating a lot of short lived objects isn’t always bad... modern JVMs are optimized for this. But if you’re doing it in tight loops or in performance critical paths, it can hurt.
Examples:
Boxing primitives Integer &| Double in hot paths? That adds up.
Creating new Stringobjects from substrings for no reason?... We all know that person.
Logging full stack traces every 5 milliseconds? Please stop.
Ye Ol' String... Everyone’s favourite (probably the first data type you learnt when writing a HelloWorld app) but it’s also a memory hog if you’re not careful.
Every String in Java is immutable. So str += "To Infinity And Beyond!" inside a loop? That’s creating a whole new String each time (also your memory usage really will go to infinity and beyond... sorry ha!).
Some history for you (Something I learnt recently), old school Java used to store strings in the PermGen. Sure that's gone in newer versions BUT poorly managed strings still cause bloat.
This one's for free: Use StringBuilder or StringBuffer when building strings in loops.Prior to Java 7, String literal in pool may be collected only if perm gen is included in collection (not every Full/Old GC includes perm gen in scope).
Tuning the JVM Isn’t Cheating
The JVM is powerful, but it doesn’t know your app. That’s your job.
Set appropriate -Xms and -Xmx Heap size values.
Choose the right garbage collector for your use case (G1, ZGC, etc).
Monitor using tools like VisualVM, jConsole, or others to get visibility into what’s happening under the hood.
Use the -XX:+HeapDumpOnOutOfMemoryError flag. When things go bad and you want to know why.
You don’t need to be a JVM engineer to write memory efficient code... But you do need to know how memory works. Blind trust in the garbage collector will only get you so far - maybe pretty far (depending on what you're building) but when your memory usage is going to the moon? Goodluck, I hope you have lots of coffee and a nice boss.
So take the time:
- Look at your object lifecycles.
- Watch your collections.
- Avoid unnecessary allocations.
You'll eventually start doing these things subconsciously..
And yes... every now and then... read a heap dump. It builds character.
A few things I’d love to discuss:
- What memory profiling tool do you swear by?
- Ever had a memory leak in Java that gave you nightmares?
- Are modern GC algorithms good enough to let us “stop caring”?
Still no gin,
Rus