Работа с памятью

Статус
В этой теме нельзя размещать новые ответы.

CrashX

В прошлом XSiteCMS
Регистрация
6 Июн 2008
Сообщения
682
Реакции
114
в PHP немозможно работать с памятью, увы но кажды раз приходтся придумывать велосипеды

очередной велосипед

есть классы типа этого
PHP:
<?php

/**
 * $Revision: 400 $
 * $Author: CrashX $
 * $Date: 2011-04-05 13:44:51 +0700 (Вт, 05 апр 2011) $
 * $LastChangedDate: 2011-04-05 13:44:51 +0700 (Вт, 05 апр 2011) $
 * $Id: document.php 400 2011-04-05 06:44:51Z CrashX $
 * Copyright © CrashX <XSiteCMS@gmail.com>
 * Всі права захищено © CrashX
 */
if (!defined('_SHELL'))
  die();

/**
 * Класс документа
 */
class Document {

  var $version = 0.01;
  public $title = null;
  public $description = null;
  public $keyword = null;
  public $style = null;
  public $script = null;
  public $header = null;

  public function __construct() {
    $this->keyword = new Keyword();
    $this->description = new Description();
    $this->title = new Title();
  }

  /**
   * @global Engine $engine
   * @return <type>
   */
  function clear() {
    global $engine;
    $this->description->clear();
    $this->keyword->clear();
    $this->title->clear();
  }

  /**
   * @global Engine $engine
   */
  function headers() {
    global $engine;
    header("Content-Type: text/html; charset=" . $engine->language->get('CHARSET'));
    header("Cache-Control: no-store, no-cache, must-revalidate");
    header("Cache-Control: post-check=0, pre-check=0", false);
    header("Pragma: no-cache");
    header("Expires: " . gmdate("D, d M Y H:i:s", 0) . " GMT");
    header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
  }

  /**
   * @global Engine $engine
   * @return <type>
   */
  function meta() {
    global $engine;
    /**
      <meta http-equiv="cache-control" content="no-cache" />
      <meta http-equiv="last-modified" content="' . gmdate('D, d M Y H:i:s') . ' GMT" />
     */
    return '<meta charset=' . $engine->language->get('CHARSET') . ' />
  <meta http-equiv="content-type" content="text/html; charset=' . $engine->language->get('CHARSET') . '" />
  <meta name="title" content="' . $this->title->get() . '" />
  <meta name="keywords" content="' . $this->keyword->get() . '" />
  <meta name="description" content="' . $this->description->get() . '" />
  <meta name="abstract" content="' . $this->description->get() . '" />
  <meta name="generator" content="' . GENERATOR . '" />'
    . (GOOGLE ? "\n" . '  <meta name="verify-v1" content="' . GOOGLE . '" />' : '')
    . (YANDEX ? "\n" . '  <meta name="yandex-verification" content="' . YANDEX . '" />' : '')
    . (WEBMONEY ? "\n" . '  <meta name="webmoney.attestation.label" content="' . WEBMONEY . '" />' : '')
    . "\n" . '  <link rel="alternate" href="feed.rss" type="application/rss+xml">
  <link rel="icon" href="favicon.ico" type="image/x-icon">
  <link rel="shortcut icon" href="favicon.ico" type="image/x-icon">';
  }

  public function scripts($string=null) {
// код
    return;
 
  }

}

/**
 * Класс ключевых влов
 */
class Keyword {

  var $version = 0.01;
  public $config = array('words' => 15, 'min' => 5, 'max' => 25);
  private $keywords = array();
//  private $endings = array("ые", "ое", "ие", "ий", "ая", "ый", "ой", "ми", "ых", "ее", "ую", "их", "ым");
  private $exceptions = array();

  /**
   *
   * @global Engine $engine
   */
  public function __construct() {
    global $engine;
    $this->keywords = preg_split("/[\s,]+/s", $engine->string->trim($engine->config['keywords']));
  }

  /**
   *
   * @global Engine $engine
   */
  function get() {
    global $engine;
    return (string) implode(", ", $this->keywords);
  }

  /**
   *
   * @global Engine $engine
   * @param <type> $key
   */
  function set($key) {
    global $engine;
    if (in_array($key, $this->keywords)):
      return false;
    else:
      $this->keywords[] = $key;
    endif;
  }

  /**
   *
   * @global Engine $engine
   */
  function clear() {
    global $engine;
    $this->keywords = array();
  }

  /**
   *
   * @global Engine $engine
   * @param string $text
   * @return mixed
   */
  function generate($text=null) {
    global $engine;
  // поиск ключей
    return $words;
  }

}

/**
 * Класс составления описания страницы
 */
class Description {

  var $version = 0.01;
  public $config = array('length' => 300);
  private $description = array();
  private $synonyms = array('search' => 'replace');

  /**
   *
   * @global Engine $engine
   */
  public function __construct() {
    global $engine;
    $this->description = $engine->config['description'];
  }

  /**
   *
   * @global Engine $engine
   * @param <type> $key
   */
  function get() {
    global $engine;
    return $this->description;
  }

  /**
   *
   * @global Engine $engine
   * @param <type> $key
   */
  function set($string) {
    global $engine;
    $this->description .= $string;
  }

  /**
   *
   * @global Engine $engine
   */
  function clear() {
    global $engine;
    $this->description = null;
  }

  /**
   *
   * @global Engine $engine
   * @param string $text
   * @return mixed
   */
  function generate($text=null) {
    global $engine;
  }

}

/**
 * Класс заголовка страницы
 */
class Title {

  var $version = 0.01;
  public $config = array('length' => 300, 'separator' => ' - ');
  private $title = array();
  private $synonyms = array('search' => 'replace');

  /**
   *
   * @global Engine $engine
   */
  public function __construct() {
    global $engine;
    $this->title[] = $engine->config['title'];
  }

  /**
   *
   * @global Engine $engine
   * @param <type> $key
   */
  function get() {
    global $engine;
    return (string) implode($this->config['separator'], $this->title);
  }

  /**
   *
   * @global Engine $engine
   * @param <type> $key
   */
  function set($string) {
    global $engine;
    $this->title[] = $string;
  }

  /**
   *
   * @global Engine $engine
   */
  function clear() {
    global $engine;
    $this->title = null;
  }

  /**
   *
   * @global Engine $engine
   * @param string $text
   * @return mixed
   */
  function generate($text=null) {
    global $engine;
  }

}

//
?>

в каждом классе есть функция clear
где идет обнуление переменных, тем самым освобождая память,
не только меньше памяти есть, но и быстрее ворочает массивами, ведь проще крутануть 10 элементов чем 100

и так до чего додумался

есть результирующие фукнции
например тут это $document->meta();

идея какая
скажем мне уже ненужны другие классы
и данные в них, но я делаю ретурн... как быть с темы данными которые там остаются? они же тупо висят... беда...

я придумал следующие

когда делаю return "что-то".$this->clear();
тем самым закрываю ретурн очисткой, раз тут нельзя повесить обработчики на возврат то вот такая идея, попробовал вроде работает


может есть какой другой интересный механиз?
 

saen

Постоялец
Регистрация
6 Авг 2006
Сообщения
756
Реакции
129
А не проще удалять весь объект после того, как он отработал? То что ты тут пытаешься реализовать, это какие ненужные крошки.
 

CrashX

В прошлом XSiteCMS
Регистрация
6 Июн 2008
Сообщения
682
Реакции
114
возможно неудачныq пример,
архитектура построена так что объект хранится в реестре, но без клонирования

и может быть вызван где угодно, например мне нужно получить состояние текущих данных, или рассчитать что то, поэтому удалять нельзя. удаляю только при генерации шаблона тк там уже нельзя взаимодействовать с системой, она там очищается и выдват шаблон, но когда работаю

модули и блоки они используют возможности пересекаемых объектов, интересно можно ли как нибудь повесить свое событие на return
как например __sleep будет вызван сразу при применении к объекту функции serialize

крошаками я бы назвал, 600 месаг, объем до очистки 4м после 2м )
 

saen

Постоялец
Регистрация
6 Авг 2006
Сообщения
756
Реакции
129
тебя понять очень трудно, вроде по-русски пишешь. ты сам-то читаешь что написал? попробуй return на __get(), где после возврата будешь очищать то что нужно
 

CrashX

В прошлом XSiteCMS
Регистрация
6 Июн 2008
Сообщения
682
Реакции
114
читаю, просто в голове сумбур

__get() при обращении к не существующему свойству или методу, по другому он не сработает.

в топку, переписываю код

у меня огромные выборки от 2 до 8к записей, и поэтому с памятью стараюсь работать правильно, что бы не нагружать сервер. пока хостер не ругался.

онлайн на проекте около 100 человек 1 - скрипт жрет 16 мег. в пике. пик ~5-10мс далее спад до 8 рабочих и там уже парсинг.
 

saen

Постоялец
Регистрация
6 Авг 2006
Сообщения
756
Реакции
129
читаю, просто в голове сумбур

__get() при обращении к не существующему свойству или методу, по другому он не сработает.

в топку, переписываю код

у меня огромные выборки от 2 до 8к записей, и поэтому с памятью стараюсь работать правильно, что бы не нагружать сервер. пока хостер не ругался.

онлайн на проекте около 100 человек 1 - скрипт жрет 16 мег. в пике. пик ~5-10мс далее спад до 8 рабочих и там уже парсинг.
Ну а что так трудно переписать класс под работу с несуществующими свойствами? все свойства загоняешь в 1 массив, скажем $data. И при обращении к несуществующему свойству будет идти проверка, есть ли такой элемент в массиве $data.

к примеру так:
PHP:
class Myclass
{
     public $data = array(
     'a' => 'blabla',
     'b' => array(1,2,3,4)
     );

     public function __get($name)
     {
          if(isset($this->data[$name]) && !method_exists($this, $name))
          {
              $response = $this->data[$name];
              $this->data[$name] = null;
              return $response;
           }
           return false;
     }
}

$class = new Myclass();
$a = $class->a;
 

CrashX

В прошлом XSiteCMS
Регистрация
6 Июн 2008
Сообщения
682
Реакции
114
это переливание из пустого в порожнее
смотри
ты сначала загрузил данные в $this->data[$name]
поработал с ними, потом вызываешь фукнцию что бы она тебе вернула их в готовом виде (предварительно что то сделав)
ты их получил а начал работу, но объем памяти занимаемый, только растет
1 тк ты не очистил при передаче переменную, она не очистилась сама.
поэтому лучше использовать объекты, тк переменную объекты можно очисть из вне. те приходтся либо руками написать $ect->param=null
либо написать функцию по очисте класса, и вызывать руками, тк нет механизка для вызова после совершения ретурн, именно поэтому я преположил что можно присать return $this-param.$this->clear();
в клеар $this-param=null; без ретурна. все. это работает как костыль, но память освобождается.
либо после вызова где то вызвать этот метод издалека самому.

а если как ты прдложил
перекладывать в переменную то она (новая переменная) просто повиснет в оперативе. тем самым займет место до окончания выполения скрипта.

у меня проблема только в шаблонизаторе (аналогичный дле) осталась, он быстрый, и удобный но у него общее хранилище, теперь думаю о разделении хранилищ для блоков, панелей, модулей и самого шаблона отдельно. что бы следить за ними было проще.
 

saen

Постоялец
Регистрация
6 Авг 2006
Сообщения
756
Реакции
129
это переливание из пустого в порожнее
смотри
ты сначала загрузил данные в $this->data[$name]
поработал с ними, потом вызываешь фукнцию что бы она тебе вернула их в готовом виде (предварительно что то сделав)
ты их получил а начал работу, но объем памяти занимаемый, только растет
1 тк ты не очистил при передаче переменную, она не очистилась сама.
поэтому лучше использовать объекты, тк переменную объекты можно очисть из вне. те приходтся либо руками написать $ect->param=null
либо написать функцию по очисте класса, и вызывать руками, тк нет механизка для вызова после совершения ретурн, именно поэтому я преположил что можно присать return $this-param.$this->clear();
в клеар $this-param=null; без ретурна. все. это работает как костыль, но память освобождается.
либо после вызова где то вызвать этот метод издалека самому.

а если как ты прдложил
перекладывать в переменную то она (новая переменная) просто повиснет в оперативе. тем самым займет место до окончания выполения скрипта.

у меня проблема только в шаблонизаторе (аналогичный дле) осталась, он быстрый, и удобный но у него общее хранилище, теперь думаю о разделении хранилищ для блоков, панелей, модулей и самого шаблона отдельно. что бы следить за ними было проще.
1) Научись уже грамотно писать, ничерта не понятно о чем пишешь!
2) Ты уверен, что после того, как переменная отработала внутри функции, сборщик мусора ее не удаляет?
 

Alternator

Постоялец
Регистрация
23 Мар 2009
Сообщения
295
Реакции
145
в PHP начиная с версии 5.3 есть нормальный сборщик мусора, и в дополнение gc_collect_cycles()
И объект удаляется после того как будет удалена последняя ссылка на него. Возможно не сразу, но много неудаленных объектов не держится, и оператива понапрасну не расходуется.

В PHP более ранних версий, была проблема с очисткой циклических ссылок.
Но, все остальные виды ссылок прекрасно удаляются.

У тебя, как видим древовидная структура ссылок, и вершиной айсберга является центральное хранилище.
Так, после того, как ты обратился к объекту из реестра, и точно знаешь, что он тебе уже не нужен, то удаляй его, и все его свойства(если на них больше нету ссылок), также будут очищены из памяти.
Если же ты не знаешь момент, когда последний раз используешь объект, и когда его нужно удалять, то и вопрос исчерпан: ибо зачем удалять свойства у объекта и подобъектов, если они могут снова понадобится? или ты заново востанавливать почищенные данные собираешься? тогда у тебя взамен оперативы проблемы со скоростью начнутся
 

CrashX

В прошлом XSiteCMS
Регистрация
6 Июн 2008
Сообщения
682
Реакции
114
saen
да уверен, сборщик не работает, как нужно смотрю, как встроенными функциями, так и отладчиком.
специально, переписывал тяжелые функции что бы без свойств (хранилища в объекте) работать.
структура
Код:
Engine (корень он же реестр, нет хранилища, только текущая конфигурация)
Engine->cache (воздействие с file, string, хранилище свое)
Engine->control (воздействие metadata)
Engine->curl
Engine->date (воздействие с string)
Engine->db 
Engine->debug
Engine->document (воздействие с string, metadata и внутренними классами, хранилище свое)
Engine->document->Title
Engine->document->key
Engine->document->desc
Engine->element
Engine->encryption
Engine->file
Engine->gzip
Engine->hall (воздействие с user, хранилище свое)
Engine->language (воздействие с file, хранилище свое)
Engine->metadata (воздействие с file, cache, хранилище свое)
Engine->module (воздействие с file, хранилище свое)
Engine->string
Engine->template (воздействие с file, string, cache, хранилище свое)
Engine->user
Engine->variable (воздействие с file, metadata)
центрального хранилища нет, у каждого класса оно свое.
у меня проблема в том что на малых объемах данных, невидно расхода оперативной памяти, те когда идет выборка 10-500 записей,
но при больше видно.
в некоторых классах есть углубления, до 3-4 уровня, но это специфические модули.
наглядный пример утечки
было
PHP:
function result($type=MYSQL_ASSOC) { 
    global $engine, $mem; 
    if ($this->cached && $this->load): 
       $rec = null; 
        @list(, $rec) = @each($this->cache); 
        return $rec; 
    else: 
      return mysqli_fetch_array($this->id, $type); 
    endif; 
  }
тут память постоянно росла
стало
PHP:
function result($type=MYSQL_ASSOC) { 
    global $engine, $mem; 
    if ($this->cached && $this->load): 
      return array_shift($this->cache); 
    else: 
      return mysqli_fetch_array($this->id, $type); 
    endif; 
  }
тут уменьшается, а подобные алгоритмы используются во многих CMS
 
Статус
В этой теме нельзя размещать новые ответы.
Сверху