当前位置: 首页 > 面试题库 >

MySQL错误1436:线程堆栈溢出,带有简单查询

东门清夷
2023-03-14
问题内容

我在表上进行了非常简单的更新,这也触发了一个非常简单的触发器,这给了我错误

#1436 - Thread stack overrun:  6136 bytes used of a 131072 byte stack, and 128000 bytes needed.

我执行的查询:

UPDATE field_values SET value = 'asaf' WHERE field_values.id =1

值字段是一个text字段。因此,从理论上讲,它可能变得安静。在这种情况下情况并非如此。

正在执行的触发器是:

DELIMITER $$
    CREATE TRIGGER field_value_update_trigger BEFORE UPDATE ON community_fields_values
    FOR EACH ROW BEGIN
      INSERT INTO user_field_log (user_id, field_id, value) VALUES (NEW.user_id, NEW.field_id, NEW.value);
    END;
$$
DELIMITER ;

为什么显示此错误?好像没有涉及任何繁重的查询。另请注意,数据库几乎是空的,其中只有2行,community_fields_valuesuser_field_log

MySQL版本:5.1.44


问题答案:

错误1436对应于mysql 5.1代码中的ER_STACK_OVERRUN_NEED_MORE:

malff@linux-8edv:include> pwd
/home/malff/BZR_TREE/mysql-5.1/include
malff@linux-8edv:include> grep 1436 mysqld_error.h
#define ER_STACK_OVERRUN_NEED_MORE 1436

打印出现错误的代码在sql / sql_parse.cc中,函数check_stack_overrun():

bool check_stack_overrun(THD *thd, long margin,
                         uchar *buf __attribute__((unused)))
{
  long stack_used;
  DBUG_ASSERT(thd == current_thd);
  if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
      (long) (my_thread_stack_size - margin))
  {
    char ebuff[MYSQL_ERRMSG_SIZE];
    my_snprintf(ebuff, sizeof(ebuff), ER(ER_STACK_OVERRUN_NEED_MORE),
                stack_used, my_thread_stack_size, margin);
    my_message(ER_STACK_OVERRUN_NEED_MORE, ebuff, MYF(ME_FATALERROR));

从看到的值中,margin为128000,my_thread_stack_size为131072。

试图保留128000个字节的对check_stack_overrun()的唯一调用来自:

bool
sp_head::execute(THD *thd)
{
  /* Use some extra margin for possible SP recursion and functions */
  if (check_stack_overrun(thd, 8 * STACK_MIN_SIZE, (uchar*)&old_packet))
    DBUG_RETURN(TRUE);

STACK_MIN_SIZE的值为16000:

malff@linux-8edv:sql> pwd
/home/malff/BZR_TREE/mysql-5.1/sql
malff@linux-8edv:sql> grep STACK_MIN_SIZE *.h
mysql_priv.h:#define STACK_MIN_SIZE          16000   // Abort if less stack during eval.

到目前为止,一切都按预期对服务器起作用:

  • 该代码执行一个触发器,该触发器通过sp_head :: execute实现。
  • MySQL运行时检查堆栈上至少有128000个字节
  • 该检查失败(正确地如此),并且触发器执行以错误结束。

MySQL触发器执行所需的堆栈数量并不取决于触发器复杂性本身,也不取决于所涉及表的内容/结构。

在什么 真正 的问题是,我想,为什么只在128K(131072)的thread_stack。

在sql / mysqld.cc中,名为“ thread_stack”的服务器变量在C中作为“ my_thread_stack_size”实现:

  {"thread_stack", OPT_THREAD_STACK,
   "The stack size for each thread.", &my_thread_stack_size,
   &my_thread_stack_size, 0, GET_ULONG, REQUIRED_ARG,DEFAULT_THREAD_STACK,
   1024L*128L, ULONG_MAX, 0, 1024, 0},

1024L * 128L是此参数的最小值。缺省值为DEFAULT_THREAD_STACK,它在include / my_pthread.h中定义:

#ifndef DEFAULT_THREAD_STACK
#if SIZEOF_CHARP > 4
/*
  MySQL can survive with 32K, but some glibc libraries require > 128K stack
  To resolve hostnames. Also recursive stored procedures needs stack.
*/
#define DEFAULT_THREAD_STACK    (256*1024L)
#else
#define DEFAULT_THREAD_STACK    (192*1024)
#endif
#endif

因此,默认情况下,堆栈大小应为192K(32位)或256K(64位体系结构)。

首先,检查如何编译mysqld二进制文件,以查看默认值:

malff@linux-8edv:sql> pwd
/home/malff/BZR_TREE/mysql-5.1/sql
malff@linux-8edv:sql> ./mysqld --no-defaults --verbose --help | grep thread_stack
...
  --thread_stack=#    The stack size for each thread.
thread_stack                      262144

在我的系统上,我在64位平台上获得256K。

如果有不同的值,也许有人用不同的编译选项来构建服务器,例如-
DDEFAULT_THREAD_STACK(或只是修改了源代码)…在这种情况下,我会质疑二进制文件的来源。

其次,检查my.cnf以获取配置文件本身提供的默认值。显式地将值设置为thread_stack的行(并具有较低的值)将最终导致看到的错误。

最后,检查服务器日志文件中是否存在此类错误(请参见sql / mysqld.cc):

sql_print_warning("Asked for %lu thread stack, but got %ld",
                  my_thread_stack_size, (long) stack_size);

服务器代码调用:

  • pthread_attr_setstacksize()设置堆栈大小
  • pthread_attr_getstacksize()验证线程真正具有多少堆栈,如果pthread库使用较少,则会在日志中抱怨。

长话短说,出现错误是因为thread_stack与服务器附带的默认值相比太小。可能会发生:

  • 在执行服务器的自定义构建时,具有不同的编译选项
  • 更改my.cnf文件中的默认值时
  • 如果pthread库本身出了问题(从理论上看,从阅读代码开始,我自己从未见过)。

我希望这个回答这个问题。

问候-马克·阿尔夫

更新(2014-03-11),使“如何修复”更加明显。

这很可能是在my.cnf文件中更改了thread_stack文件的默认值。

然后,如何解决这个问题很简单,找到my.cnf文件中设置thread_stack的位置,然后删除设置(信任服务器代码以提供适当的默认值,这样下次就不会再发生这种情况)或增加堆栈尺寸。



 类似资料:
  • 问题内容: 下面给出的代码显示了运行时的Stackoverflow错误。但是,如果我使另一个类CarChange创建Car的对象,它将成功运行。我是一个初学者,请执行以下代码以了解在Java中进行向上转换的重要性。 问题答案: 一个stackoverflow通常意味着您有一个无限循环。 收到此消息的原因是因为您从testdrive方法调用驱动器,并且在该方法中再次调用drive。

  • 问题内容: 我的朋友有一个小问题,我已不知所措。他编写了一个简单的(在学校就读到的)QuickSort算法,它产生了StackOverflow错误。我知道这意味着它在某处多次调用自身递归,但是我无法获得逻辑错误- 请帮助我! 这是代码(我在这里省略了一些代码,仅是为了在2个文本区域中显示它): 它的名称如下: 但是,如果我们将其称为2个数字相同,则不会产生溢出。 如果需要更多代码,这是pasteb

  • 我有一个类 Delete 我想使用 Gson 库将其转换为 json,但是当我转换它时,它会抛出 这是我的类 这里是枚举类DeleteStatus.scala 删除原因.scala 以下是我如何在Json转换 但它抛出以下异常 请帮助其中的错误

  • 我有一个执行快速排序的应用程序。在我开始给它一些更大的数字(我第一次得到它是10000000)之前,它工作得很好。我知道是由递归引起的,但我不明白为什么我的应用程序会因此而崩溃。如有任何建议,将不胜感激。这是我的密码:

  • 我有一个文件解析器代码,偶尔会在m.matches()上出现堆栈溢出错误(其中m是匹配器)。 我再次运行我的应用程序,它解析相同的文件,没有堆栈溢出。 我的模式确实有点复杂。它基本上是一组可选的零长度正lookahead,其中包含命名组,这样我就可以匹配一组变量名/值对,而不考虑它们的顺序。但我认为,如果某个字符串会导致堆栈溢出错误,它总是会导致它。。。不只是有时候。。。有什么想法吗? 我的模式

  • 问题内容: TL; DR: 将任何非内置函数添加到Array.prototype AND Function.prototype将导致IE8本机JSON解析器在解析包含数组的任何JSON时发生堆栈溢出,但仅当您还传递了reviver函数时放入JSON.parse()。 最初这是一个问题,但我回答了我自己的原始问题,所以现在我要问:有人能想到此IE8错误的解决方法,该方法不涉及消除所有修改Array.