fukuball

fukuball

Member Since 2 Years Ago

Experience Points 13,720
Experience Level 3

1,280 experience to go until the next level!

In case you were wondering, you earn Laracasts experience when you:

  • Complete a lesson — 100pts
  • Create a forum thread — 50pts
  • Reply to a thread — 10pts
  • Leave a reply that is liked — 50pts
  • Receive a "Best Reply" award — 500pts
Lessons Completed 136
Lessons
Completed
Best Reply Awards 0
Best Reply
Awards
  • start-engines Created with Sketch.

    Start Your Engines

    Earned once you have completed your first Laracasts lesson.

  • first-thousand Created with Sketch.

    First Thousand

    Earned once you have earned your first 1000 experience points.

  • 1-year Created with Sketch.

    One Year Member

    Earned when you have been with Laracasts for 1 year.

  • 2-years Created with Sketch.

    Two Year Member

    Earned when you have been with Laracasts for 2 years.

  • 3-years Created with Sketch.

    Three Year Member

    Earned when you have been with Laracasts for 3 years.

  • 4-years Created with Sketch.

    Four Year Member

    Earned when you have been with Laracasts for 4 years.

  • 5-years Created with Sketch.

    Five Year Member

    Earned when you have been with Laracasts for 5 years.

  • school-session Created with Sketch.

    School In Session

    Earned when at least one Laracasts series has been fully completed.

  • welcome-newcomer Created with Sketch.

    Welcome To The Community

    Earned after your first post on the Laracasts forum.

  • full-time-student Created with Sketch.

    Full Time Learner

    Earned once 100 Laracasts lessons have been completed.

  • pay-it-forward Created with Sketch.

    Pay It Forward

    Earned once you receive your first "Best Reply" award on the Laracasts forum.

  • subscriber-token Created with Sketch.

    Subscriber

    Earned if you are a paying Laracasts subscriber.

  • lifer-token Created with Sketch.

    Lifer

    Earned if you have a lifetime subscription to Laracasts.

  • lara-evanghelist Created with Sketch.

    Laracasts Evangelist

    Earned if you share a link to Laracasts on social media. Please email [email protected] with your username and post URL to be awarded this badge.

  • chatty-cathy Created with Sketch.

    Chatty Cathy

    Earned once you have achieved 500 forum replies.

  • lara-veteran Created with Sketch.

    Laracasts Veteran

    Earned once your experience points passes 100,000.

  • 10k-strong Created with Sketch.

    Ten Thousand Strong

    Earned once your experience points hits 10,000.

  • lara-master Created with Sketch.

    Laracasts Master

    Earned once 1000 Laracasts lessons have been completed.

  • laracasts-tutor Created with Sketch.

    Laracasts Tutor

    Earned once your "Best Reply" award count is 100 or more.

  • laracasts-sensei Created with Sketch.

    Laracasts Sensei

    Earned once your experience points passes 1 million.

  • top-50 Created with Sketch.

    Top 50

    Earned once your experience points ranks in the top 50 of all Laracasts users.

11 Jul
1 week ago

fukuball left a reply on Laravel 5.8 Memory Leak

@click I think $item->setRelations([]); solves my problem, thanks!

fukuball left a reply on Laravel 5.8 Memory Leak

@cronix Yes, I disabled query logging.

10 Jul
1 week ago

fukuball left a reply on Laravel 5.8 Memory Leak

@snapey If the underlying mechanism is expanding the member of $albums, then we can explain why the memory grows, but it can't free the memory by $album->setRelation('songs', null);, I think it is a memory leak, do you think it's a memory leak?

fukuball left a reply on Laravel 5.8 Memory Leak

@nash They want me ask here.

fukuball left a reply on Laravel 5.8 Memory Leak

They want me ask here.

fukuball left a reply on Laravel 5.8 Memory Leak

@cronix I know it's a N+1 query, but N+1 query should not cause the memory leak, I discuss by cases in the main article above.

09 Jul
1 week ago

fukuball left a reply on Laravel 5.8 Memory Leak

@staudenmeir @click Actual code looks like this: (also updated on GitHub)

$albums = Album::take(10000)->get();

$i = 1;
foreach ($albums as $album) {
    $songs = $album->songs;
    echo "$album->id start \n";
    echo "#executions = " . $album->id . " - mem: " . memory_get_usage() . "\n";
    echo "$album->id end \n";
    $album->setRelation('songs', null);
    unset($songs);
    unset($album);
    $i++;
}

$album->setRelation('songs', null); still can do the trick, the memory goes up and never come back.

...
1261 start 
#executions = 1261 - mem: 14746184
1261 end 
1262 start 
#executions = 1262 - mem: 14746560
1262 end 
1263 start 
#executions = 1263 - mem: 14746936
1263 end 
1264 start 
#executions = 1264 - mem: 14747320
1264 end 
1265 start 
#executions = 1265 - mem: 14747696
1265 end 
1266 start 
#executions = 1266 - mem: 14748064
1266 end 
1267 start 
#executions = 1267 - mem: 14748456
1267 end 
1268 start 
#executions = 1268 - mem: 14748816
1268 end 
1269 start 
#executions = 1269 - mem: 14749200
1269 end
...

fukuball left a reply on Laravel 5.8 Memory Leak

@staudenmeir @click I try to unset the variables every iteration, the memory still grows, is there any way to free the memory?

$albums = Album::take(10000)->get();
foreach ($albums as $album) {
    $songs = $album->songs; // cause memory leak
    unset($songs);
    unset($album); // can't free the memory, I think in this case is memory leak
}
04 Jul
2 weeks ago

fukuball started a new conversation Laravel 5.8 Memory Leak

Demo Repo

https://github.com/fukuball/Leak58

Laravel memory leak example

It is normal to loop and process data in script, I found some weird memory leak in Laravel, and wonder how this happened. I have some workaround to prevent the memory leak, but it can't solve the root cause, so I provide some cases to demo the memory leak, hope someone can solve this issue.

Install

$ composer install
$ php artisan migrate

Data seeding

$ php artisan leak_test_data

Usage

Case 1

This first case demo a simple loop cause the memory leak:

$ php artisan leak_test leak

Some details:

$albums = Album::take(10000)->get();
foreach ($albums as $album) {
    $songs = $album->songs; // cause memory leak
}

And we can see the memory goes up and never come back:

...
550 start
#executions = 550 - mem: 14799640
550 end
551 start
#executions = 551 - mem: 14801728
551 end
552 start
#executions = 552 - mem: 14803800
552 end
553 start
#executions = 553 - mem: 14805872
553 end
554 start
#executions = 554 - mem: 14807944
554 end
555 start
#executions = 555 - mem: 14810024
555 end
556 start
#executions = 556 - mem: 14812112
556 end
557 start
#executions = 557 - mem: 14814192
557 end
...

I know there is N+1 query in it, but simple loop with simple qurey should not cause memory leak, it happend in Laravel.

Case 2

This second case demo a simple loop with N+1 query, but no memory leak:

$ php artisan leak_test no_leak

Some details:

$albums = Album::take(10000)->get();
foreach ($albums as $album) {
    $songs = $album->songs()->get(); // why this don't cause the memory leak?
}

We can see the memory usage is stable:

...
439 start
#executions = 439 - mem: 13659472
439 end
440 start
#executions = 440 - mem: 13659456
440 end
441 start
#executions = 441 - mem: 13659464
441 end
442 start
#executions = 442 - mem: 13659456
442 end
443 start
#executions = 443 - mem: 13659456
443 end
444 start
#executions = 444 - mem: 13659464
444 end
445 start
#executions = 445 - mem: 13659456
445 end
446 start
#executions = 446 - mem: 13659464
446 end
...

This is reasonable, although there is N+1 query, but should not cause memory leak.

Case 3

Third case demo a simple loop and use "with" to solve N+1 query.

$ php artisan leak_test leak_solve_by_with

Some details:

$albums = Album::with(['songs'])->take(10000)->get();
foreach ($albums as $album) {
    $songs = $album->songs; // cause memory leak
}

We can see the memory usage is always same:

...
1239 start
#executions = 1239 - mem: 16015944
1239 end
1240 start
#executions = 1240 - mem: 16015944
1240 end
1241 start
#executions = 1241 - mem: 16015944
1241 end
1242 start
#executions = 1242 - mem: 16015944
1242 end
1243 start
#executions = 1243 - mem: 16015944
1243 end
1244 start
#executions = 1244 - mem: 16015944
1244 end
1245 start
#executions = 1245 - mem: 16015944
1245 end
1246 start
#executions = 1246 - mem: 16015944
1246 end
1247 start
#executions = 1247 - mem: 16015944
1247 end
...

This is trivial, this solve the N+1 query, get all the data first, and Laravel use the data and no need to query again and again, so if we can get all the data into the memory, the script will excute perfectly.

Case 4

This case demo a common case when we write OOP, we use use some method in model, and model will get the necessary data to proceed the work.

$ php artisan leak_test leak_weird

Some details:

$albums = Album::take(10000)->get();
foreach ($albums as $album) {
    $songs = $album->processSomethingToReturn();
}

// in Album.php
public function processSomethingToReturn()
{
    $songs = $this->songs; // this cause memory leak
    // do something here...
    return $songs;
}

And we can see the memory goes up and never come back:

...
453 start
#executions = 453 - mem: 14598224
453 end
454 start
#executions = 454 - mem: 14600296
454 end
455 start
#executions = 455 - mem: 14602376
455 end
456 start
#executions = 456 - mem: 14604456
456 end
457 start
#executions = 457 - mem: 14606528
457 end
458 start
#executions = 458 - mem: 14608616
458 end
459 start
#executions = 459 - mem: 14610688
459 end
460 start
#executions = 460 - mem: 14612760
460 end
461 start
#executions = 461 - mem: 14614840
461 end
...

This is common to write some method for "Encapsulation", we don't need to know the detail, just call the method to do what we want. But in this case we got memory leak.

Case 5

In this final case we use walkaround to solve the memory leak by "with" magic:

$ php artisan leak_test leak_solve_by_with_weird

Some details:

$albums = Album::with(['songs'])->take(10000)->get();
foreach ($albums as $album) {
    $songs = $album->processSomethingToReturn();
}

// in Album.php
public function processSomethingToReturn()
{
    $songs = $this->songs; // this cause memory leak
    // do something here...
    return $songs;
}

We can see the memory usage is always the same:

...
1240 start
#executions = 1240 - mem: 16015952
1240 end
1241 start
#executions = 1241 - mem: 16015952
1241 end
1242 start
#executions = 1242 - mem: 16015952
1242 end
1243 start
#executions = 1243 - mem: 16015952
1243 end
1244 start
#executions = 1244 - mem: 16015952
1244 end
1245 start
#executions = 1245 - mem: 16015952
1245 end
1246 start
#executions = 1246 - mem: 16015952
1246 end
1247 start
#executions = 1247 - mem: 16015952
1247 end
1248 start
#executions = 1248 - mem: 16015952
1248 end
...

This walkaround solve the memory leak, but really wired, in "Encapsulation" principle, we shoud not to know the detail of method, so we use with(['songs']) in advence is really wired, this should not happend when we write code.

Apparently we shold solve the root cause of memory leak. Why $this->songs in loop cause memory leak but $this->songs()->get() not?