Memory usage
Ik ben bezig om een groot bestand te parsen i.c.m. met Symfony2 en Doctrine. Nadat er ongeveer 310 regels krijg ik een foutmelding te zien dat ik over de 128 MB kom. Zoals je kan zien heb ik om te proberen dit op te lossen een paar regels onderaan toegevoegd met unset. Dit vermindert het geheugengebruik echter niet, het wordt juist meer (getest met memory_get_usage). Wat kan ik doen om mijn geheugen te minimaliseren? Bij regel 300 ben ik namelijk nog niet eens op de 20%.
Als jullie meer code nodig hebben, zeggen jullie het maar. Ik ga niet meteen alles posten, dat is nogal veel.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<?php
/**
* @param string $line
*/
private function parseStudentLine($line) {
$parts = explode(chr(9), $line);
$student = $this->studentEntityRepository->findOneBy(array('code' => $parts[0]));
if (is_null($student)) {
$student = new Student($parts[0], $parts[1], $parts[2], $parts[3], $this->school);
$this->entityManager->persist($student);
$this->logger->debug(sprintf('Student %d (%s %s %s) added to database', $student->getCode(), $student->getFirstName(), $student->getInsertions(), $student->getLastName()));
}
$timetable = new Timetable($student, $this->startDate);
unset($parts[0], $parts[1], $parts[2], $parts[3]);
$lesson = null;
foreach ($parts as $part) {
if (strlen(trim($part)) == 0 || trim($part) == '0') continue;
$lesson = $this->parseLesson($part);
$foundLesson = $this->lessonEntityRepository->findOneBy(array('code' => $lesson->getCode()));
if ($foundLesson === null) {
$this->entityManager->persist($lesson);
} else {
$lesson = $foundLesson;
}
$timetable->addLesson($lesson);
}
$this->entityManager->persist($timetable);
$this->entityManager->flush();
$this->logger->info(sprintf('Added timetable for student %d (%s %s %s)', $student->getCode(), $student->getFirstName(), $student->getInsertions(), $student->getLastName()));
$this->entityManager->detach($timetable);
$this->entityManager->detach($student);
/** @var $lesson Lesson */
foreach ($timetable->getLessons() as $lesson) {
/** @var $teacher Teacher */
foreach ($lesson->getTeachers() as $teacher) {
$teacher = null;
unset($teacher);
}
$lesson = null;
unset($lesson);
}
$timetable = null;
unset($timetable);
$student = null;
unset($student);
$parts = null;
unset($parts);
}
?>
/**
* @param string $line
*/
private function parseStudentLine($line) {
$parts = explode(chr(9), $line);
$student = $this->studentEntityRepository->findOneBy(array('code' => $parts[0]));
if (is_null($student)) {
$student = new Student($parts[0], $parts[1], $parts[2], $parts[3], $this->school);
$this->entityManager->persist($student);
$this->logger->debug(sprintf('Student %d (%s %s %s) added to database', $student->getCode(), $student->getFirstName(), $student->getInsertions(), $student->getLastName()));
}
$timetable = new Timetable($student, $this->startDate);
unset($parts[0], $parts[1], $parts[2], $parts[3]);
$lesson = null;
foreach ($parts as $part) {
if (strlen(trim($part)) == 0 || trim($part) == '0') continue;
$lesson = $this->parseLesson($part);
$foundLesson = $this->lessonEntityRepository->findOneBy(array('code' => $lesson->getCode()));
if ($foundLesson === null) {
$this->entityManager->persist($lesson);
} else {
$lesson = $foundLesson;
}
$timetable->addLesson($lesson);
}
$this->entityManager->persist($timetable);
$this->entityManager->flush();
$this->logger->info(sprintf('Added timetable for student %d (%s %s %s)', $student->getCode(), $student->getFirstName(), $student->getInsertions(), $student->getLastName()));
$this->entityManager->detach($timetable);
$this->entityManager->detach($student);
/** @var $lesson Lesson */
foreach ($timetable->getLessons() as $lesson) {
/** @var $teacher Teacher */
foreach ($lesson->getTeachers() as $teacher) {
$teacher = null;
unset($teacher);
}
$lesson = null;
unset($lesson);
}
$timetable = null;
unset($timetable);
$student = null;
unset($student);
$parts = null;
unset($parts);
}
?>
Gewijzigd op 07/12/2013 14:06:17 door Koen Vlaswinkel
Zouden de php functies als http://php.net/fgetcsv niet efficienter zijn?
Ivo P op 07/12/2013 14:11:26:
Aangezien je explode op tab doet:
Zouden de php functies als http://php.net/fgetcsv niet efficienter zijn?
Zouden de php functies als http://php.net/fgetcsv niet efficienter zijn?
Nee, niet het hele bestand heeft hetzelfde formaat, dus ik moet eerst beslissen aan welke methode ik de regel geef. fgetcsv heeft een file resource nodig, en die heb ik dus niet omdat niet alle regels hetzelfde formaat hebben.
Hoe ziet je bestand er trouwens uit? Ik denk dat het parsen een stuk simpeler kan...
En als je deze method voor elke regel uitvoert zou ik eens de flush eruit halen en die pas aan het eind van het parsen aanroepen.
hier te vinden. Je hebt gelijk dat het een beetje onnuttig is, maar ik wist geen andere manier om geheugen vrij te maken. De flush staat er zodat ik kan detachen. Ik denk eigenlijk dat dat ook gewoon gebeurt met clear(). Dit voer ik dan ook uit in de methode die deze aanroept.
Na nog wat dingen te proberen, heeft het volgende alles opgelost:
Dit geeft blijkbaar zoveel overhead dat er veel geheugen wordt verspilt.
Het bestand is Na nog wat dingen te proberen, heeft het volgende alles opgelost:
Dit geeft blijkbaar zoveel overhead dat er veel geheugen wordt verspilt.