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

Тема в разделе "PHP Pro", создана пользователем CrashX, 5 апр 2011.

Статус темы:
Закрыта.
  1. CrashX

    CrashX В прошлом XSiteCMS

    Регистр.:
    6 июн 2008
    Сообщения:
    682
    Симпатии:
    112
    в 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();
    тем самым закрываю ретурн очисткой, раз тут нельзя повесить обработчики на возврат то вот такая идея, попробовал вроде работает


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

    saen

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

    CrashX В прошлом XSiteCMS

    Регистр.:
    6 июн 2008
    Сообщения:
    682
    Симпатии:
    112
    возможно неудачныq пример,
    архитектура построена так что объект хранится в реестре, но без клонирования

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

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

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

    saen

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

    CrashX В прошлом XSiteCMS

    Регистр.:
    6 июн 2008
    Сообщения:
    682
    Симпатии:
    112
    читаю, просто в голове сумбур

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

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

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

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

    saen

    Регистр.:
    6 авг 2006
    Сообщения:
    756
    Симпатии:
    129
    Ну а что так трудно переписать класс под работу с несуществующими свойствами? все свойства загоняешь в 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;
     
  7. CrashX

    CrashX В прошлом XSiteCMS

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

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

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

    saen

    Регистр.:
    6 авг 2006
    Сообщения:
    756
    Симпатии:
    129
    1) Научись уже грамотно писать, ничерта не понятно о чем пишешь!
    2) Ты уверен, что после того, как переменная отработала внутри функции, сборщик мусора ее не удаляет?
     
  9. Alternator

    Alternator

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

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

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

    CrashX В прошлом XSiteCMS

    Регистр.:
    6 июн 2008
    Сообщения:
    682
    Симпатии:
    112
    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
     
Статус темы:
Закрыта.